CF1799G Count Voting 题解
一
首先,发现这个要求是交错的,不好直接 DP,考虑容斥。我们有两种容斥的方向:
-
把每一个恰好要
c_i 个容斥为至少要c_i 个,进行 DP。 -
把不能给自己组投票容斥,变为钦定
i 个人一定给自己组投,剩下任意。
这里我选择的是第二种容斥方法,但我觉得第一种也是可做的。
考虑一组一组地进行 DP,我们设
上式的意义即为我们枚举第
考虑如下情况:如果我们知道,第
这样
最后整理一下,我们对于每一组,先做一遍对
然后经典容斥原理:
二
总时间复杂度是
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define mod 998244353
using namespace std;
int n,m;
int c[205];
int t[205];
int b[205];
int len[200];
int slen[205];
int a[205][205];
ll f[205][205];
ll g[205][205];
ll inv[205];
ll fac[205];
ll infac[205];
inline ll C(int a,int b){return fac[a]*infac[b]%mod*infac[a-b]%mod;}
inline void init(int id){
g[0][0]=1;
for(int i=1;i<=len[id];i++){
for(int j=0;j<=len[id];j++){
g[i][j]=0;
for(int k=0;k<=j&&k<=a[id][i];k++)
(g[i][j]+=g[i-1][j-k]*infac[a[id][i]-k]%mod*C(len[id]-j+k,k))%=mod;
}
}
return ;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&c[i]);
for(int i=1;i<=n;i++) scanf("%d",&t[i]),b[i]=t[i];
sort(b+1,b+1+n);
m=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++){
t[i]=lower_bound(b+1,b+1+m,t[i])-b;
len[t[i]]++;
slen[t[i]]+=c[i];
a[t[i]][len[t[i]]]=c[i];
}
fac[0]=fac[1]=infac[0]=infac[1]=inv[1]=1;
for(int i=2;i<=n;i++){
fac[i]=fac[i-1]*i%mod;
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
infac[i]=infac[i-1]*inv[i]%mod;
}
f[0][0]=1;
for(int i=1;i<=m;i++){
init(i);
for(int j=0;j<=n;j++){
for(int k=0;k<=j&&k<=len[i];k++)
(f[i][j]+=f[i-1][j-k]*g[len[i]][k]%mod)%=mod;
}
}
ll ans=0;
for(int i=0;i<=n;i++){
ll x=f[m][i]*fac[n-i]%mod;
if(i&1) x=mod-x;
(ans+=x)%=mod;
}
printf("%lld\n",ans);
return 0;
}