CF1799G - Count Voting

我们考虑按照将所有的人分成若干个等价类,然后整组整组的考虑。

我们考虑使用生成函数来解决这个问题,设 \(x_i\) 是第 \(i\) 组得票的生成变量,生成函数的项 \(x_1^{k_1}x_2^{k_2}\cdots x_n^{k_n}\) 表示第 \(i\) 组得票 \(k_i\) 的方案种数,\(f_i\) 是第 \(i\) 组需要的票数(\(f_i=\sum_{T_j=i}{C_i}\))。\(c_i\) 是第 \(i\) 组的人数。

我们先处理人到组之间的问题,也就是把到某一组的所有贡献看作等价的,最后再处理人到人的贡献。

\(i\) 组的一个人可以向别的组投票,则他的贡献是 \(x_1+x_2+\cdots+x_{i-1}+x_{i+1}+\cdots+x_n\)。把所有人的贡献积起来就是最终的生成式。但是如果每一因式都有 \(n-1\) 项不是很好表示,我们令 \(s=x_1+x_2+\cdots +x_n\),则第 \(i\) 组的一个人的贡献就可以表示为 \(s-x_i\)

表达出最终的式子 \((s-x_1)^{c_1}(s-x_2)^{c_2}\cdots (s-x_n)^{c_n}\)

而我们要求项 \(x_1^{f_1}x_2^{f_2}\cdots x_n^{f_n}\) 的系数。

我们考虑枚举每个 \(x_i\) 中有个因子是来自于某个 \((s-x_1)\) 的后一项。假设第 \(i\) 个数中有 \(a_i\) 个是来自这里,那么剩下第 \(i\) 个数的 \(f_i-a_i\)\(x_i\) 都是来自于剩下没有被选到的 \((s-x_p)\) 中的 \(s\)

那么,首先,符号系数就是 \(\sum\)\(-1\) 相乘。

每个 \(x_i\)\(c_i\) 里选 \(a_i\) 个,贡献 \(\binom{c_i}{a_i}\)

对于所有的因式,还剩下 \(\sum(f_i-a_i)\)\(s\),分配给 \(f_1-a_1\)\(1\)\(f_2-a_2\)\(2\)\(\cdots\),就是做一次多重集 \(\binom{\sum ({f_i-a_i})}{f_1-a_1,f_2-a_2,\cdots,f_n-a_n}\)

所以,得到答案式子

\[ans=\sum_{a_i\le f_i}(-1)^{\sum a_i}\prod(\binom{c_i}{a_i})\binom{\sum ({f_i-a_i})}{f_1-a_1,f_2-a_2,\cdots,f_n-a_n} \]

\[=\sum_{a_i\le f_i}(-1)^{\sum a_i}\prod\dfrac{c_i!}{a_i!(c_i-a_i)!}\dfrac{(\sum(f_i-a_i))!}{\prod(f_i-a_i)!} \]

这个式子可以 \(dp\),设 \(dp_{i,j}\) 表示当前 \(dp\) 到第 \(i\) 个,目前 \(\sum_{x\le i}a_x=j\)\(\dfrac{1}{\prod_{x\le i}(a_x!(c_x-a_x)!(f_x-a_x)!)}\)

然后我们枚举 \(d=\sum a_i\),每次进行一次 \(dp\)\(dp\) 的转移就是枚举下一位 \(a_i\) 是多少,是 \(O(n)\) 的,预处理阶乘的逆元,看似是 \(O(n^4)\)。但是我们发现,我们每次枚举 \(a_i\) 的上界只到 \(\min(f_i,c_i)\),而 \(\sum c_i=n\),所以实际上复杂度是 \(O(n^3)\) 的。得到 \(dp_{n,d}\) 之后乘上 \((-1)^{\sum a_i}c_i!(n-d)!\)

不过我们发现,\(dp\) 过程其实和 \(d\) 无关,就可以提前预处理 \(n*n\)\(dp\) 数组,然后每次直接调用。就可以做到 \(O(n^2)\)

最后,我们因为一开始模糊化了所有组内的贡献,现在要再划分到每个人的头上去。我们发现,组内每个人要 \(s_j\) 票,总共有 \(f_i\) 票,其实又是一个多重集,就可以直接对每一组都乘上 \(\binom{\sum ({f_i})}{s_{x_1},s_{x_2},\cdots,f_{x_k}}\)

const ll P=998244353;
ll fac[205],ifac[205],n,s[205],t[205],f[205],c[205];
ll dp[205][205];
inline ll fpow(ll a,ll p){
	if(!p)return 1;
	ll res=fpow(a,p>>1);
	if(p&1)return res*res%P*a%P;
	return res*res%P;
}
inline void init(){
	fac[0]=ifac[0]=1;
	rep(i,1,200)fac[i]=fac[i-1]*i%P;
	rep(i,1,200)ifac[i]=fpow(fac[i],P-2);
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	init();
	cin>>n;
	rp(i,n)cin>>s[i];
	rp(i,n)cin>>t[i];
	rp(i,n)f[t[i]]+=s[i],c[t[i]]++;
	ll ans=0,mul=1;
	rp(i,n)mul=mul*fac[c[i]]%P;
	rep(d,0,n){
		ll res=0;
		dp[0][0]=fac[n-d];
		rp(i,n)rep(j,0,d)dp[i][j]=0;
		rep(i,0,n-1){
			rep(j,0,d)if(dp[i][j]){
				rep(k,0,min({f[i+1],c[i+1],(ll)d-j})){
					dp[i+1][j+k]=(dp[i+1][j+k]+dp[i][j]*ifac[k]%P*ifac[c[i+1]-k]%P*ifac[f[i+1]-k]%P)%P;
				}
			}
		}res=dp[n][d]*mul%P;
		if(d&1)ans=(ans-res+P)%P;
		else ans=(ans+res)%P;
	}
	rep(i,1,n)ans=ans*fac[f[i]]%P,ans=ans*ifac[s[i]]%P;
	cout<<ans%P<<endl;
	return 0;
}
//Crayan_r
posted @ 2023-02-28 21:30  jucason_xu  阅读(54)  评论(0编辑  收藏  举报