ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces 1666F. Fancy Stack

2022-07-14 16:38:02  阅读:144  来源: 互联网

标签:cnt return int LL Codeforces Fancy 1666F maxn define


传送门
\(\texttt{Difficulty:2200}\)

题目大意

一个长为 \(n(1\le n\le5000,n\) 为偶数 \()\) 的升序序列 \(a(1\le a_i\le n)\) 。将 \(a\) 中的元素重新排布,组成序列 \(b\) ,使得 \(b_1 < b_2 > b_3 < b_4 > \ldots > b_{n-1} < b_n\) 并且 \(b_2 < b_4 < b_6 < \ldots < b_n\) 。求有多少种不同的 \(b\) 序列,对 \(998244353\) 取模。

思路

考虑 \(dp\) 。我们先对原序列中元素去个重 ,去重之后原序列的大小记为 \(m\) 。\(cnt_i\) 记录第 \(i\) 大的元素的个数。我们考虑从大往小将 \(a\) 序列中元素加入 \(b\) 的过程,考虑当前元素如果可以放在偶数位 \(i\) ,那么所有 \(>i\) 的偶数位以及 \(i-1,i+1\) 两个位置都不能够有元素否则一定不会合法,放在奇数位 \(j\) 时则要求其两侧的偶数位都已经被放置,于是我们设计状态 \(f_{i,j}\) 表示第 \(i\) 到第 \(m\) 大的元素都已经被放入,且恰好 \(j\) 个被放在偶数位上的合法方案数。此时偶数位放置了那些是确定的,那么可供自由放置的奇数位也就确定了,对于重复元素的情况下,新的元素如果放偶数位则只有 \(1\) 个可以放偶数为,此外注意新加入时无论如何可放置的奇数位个数在操作完成前不会增加,记 \(s\) 为 \(cnt\) 的后缀和, \(can_j\) 为 \(j\) 个偶数位被放置时可放置的奇数位数量,注意处理边界,于是可以推导出转移方程:

\[f_{i-1,j+1}=f_{i-1,j+1}+cnt_{i-1}\cdot f_{i,j}\cdot\frac{(can_j-s_i+j)!}{(can_j-s_i+j-cnt_{i-1}+1)!} \]

\[f_{i-1,j}=f_{i-1,j}+f_{i,j}\cdot\frac{(can_j-s_i+j)!}{(can_j-s_i+j-cnt_{i-1})!} \]

初始设 \(f_{m+1,0}=1\) ,其余为 \(0\) ,答案还要去重,结果为 \(\frac{f_{1,\frac{n}{2}}}{\prod_{i=1}^m cnt_i!}\) ,复杂度 \(O(n^2)\) 。

代码

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
using LL = long long;
using LD = long double;
using ULL = unsigned long long;
using PII = pair<int, int>;
using TP = tuple<int, int, int>;
#define all(x) x.begin(),x.end()
#define mst(x,v) memset(x,v,sizeof(x))
#define mk make_pair
//#define int LL
//#define double LD
//#define lc p*2
//#define rc p*2+1
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#pragma warning(disable : 4996)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const double eps = 1e-10;
const LL MOD = 1000000007;
const LL mod = 998244353;
const int maxn = 5010;

LL T, N, A[maxn], S[maxn], cnt[maxn], F[maxn][maxn];
LL fact[maxn], invfact[maxn];

LL qpow(LL a, LL x, LL m)
{
	LL ans = 1;
	while (x)
	{
		if (x & 1)
			ans = ans * a % m;
		x >>= 1;
		a = a * a % m;
	}

	return ans % m;
}

void fact_init(LL n, LL m)
{
	fact[0] = fact[1] = 1;
	for (LL i = 2; i <= n; i++)
		fact[i] = fact[i - 1] * i % m;
	invfact[n] = qpow(fact[n], m - 2, m);;
	for (LL i = n; i > 0; i--)
		invfact[i - 1] = invfact[i] * i % m;
}

LL f(LL x)
{
	if (x < 0)
		return 0;
	return fact[x];
}

LL invf(LL x)
{
	if (x < 0)
		return 0;
	return invfact[x];
}

LL get(LL j)
{
	if (j == N / 2)
		return j;
	else
		return max(0LL, j - 1);
}

void solve()
{
	int M = 0;
	for (int i = 1; i <= N; i++)
	{
		if (cnt[i] > 0)
			cnt[++M] = cnt[i];
	}
	for (int i = 1; i <= M + 1; i++)
		S[i] = 0;
	for (int i = M; i >= 1; i--)
		S[i] = S[i + 1] + cnt[i];
	for (int i = M + 1; i >= 0; i--)
	{
		for (int j = 0; j <= N / 2; j++)
			F[i][j] = 0;
	}
	F[M + 1][0] = 1;
	for (int i = M + 1; i >= 2; i--)
	{
		for (int j = 0; j <= N / 2; j++)
		{
			LL nowcan = get(j) - (S[i] - j);
			F[i - 1][j + 1] = (F[i - 1][j + 1] + cnt[i - 1] * F[i][j] % mod * f(nowcan) % mod * invf(nowcan - (cnt[i - 1] - 1)) % mod) % mod;
			F[i - 1][j] = (F[i - 1][j] + F[i][j] % mod * f(nowcan) % mod * invf(nowcan - cnt[i - 1]) % mod) % mod;
		}
	}
	for (int i = 1; i <= M; i++)
		F[1][N / 2] = F[1][N / 2] * invfact[cnt[i]] % mod;
	cout << F[1][N / 2] << endl;
}

int main()
{
	IOS;
	fact_init(5005, mod);
	cin >> T;
	while (T--)
	{
		cin >> N;
		for (int i = 1; i <= N + 5; i++)
			cnt[i] = 0;
		for (int i = 1; i <= N; i++)
			cin >> A[i], cnt[A[i]]++;
		solve();
	}

	return 0;
}

标签:cnt,return,int,LL,Codeforces,Fancy,1666F,maxn,define
来源: https://www.cnblogs.com/Prgl/p/16478101.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有