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}\)
所以,得到答案式子
这个式子可以 \(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