[BZOJ4665] 小w的喜糖
题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=4665
Solution
考虑容斥,我们先认为同色的糖是本质不同的,不然容斥就不对,那么我们需要算出至少(k)个人糖果种类不变的方案数。
设(f_{i,j})表示前(i)种糖一共有至少(j)个人不变,直接暴力转移:
[f_{i,j}=sum_{k=0}^{cnt_i}f_{i-1,j-k}inom{cnt_i}{k}cnt_i^{underline{k}}
]
(k)是枚举当前糖不变的人数,我们先选出(k)个位置拿走,在任意地放回来,由于我们硬点了本质不同所以这玩意是对的。
由于原题中同色本质相同,所以每种情况都被算了(prod cnt_i!),答案除掉就好了。
复杂度很好证明,我们的总枚举次数大概是:
[sum_{i=1}^{n}ncdot cnt_i =O(n^2)
]
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('
');}
#define lf double
#define ll long long
#define pii pair<int,int >
#define vec vector<int >
#define pb push_back
#define mp make_pair
#define fr first
#define sc second
#define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
const int maxn = 2010;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 1e9+9;
int f[maxn][maxn],t[maxn],n,fac[maxn],ifac[maxn],inv[maxn],s[maxn];
void prepare() {
fac[0]=ifac[0]=inv[0]=inv[1]=1;
for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod;
for(int i=2;i<=n;i++) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(int i=1;i<=n;i++) ifac[i]=1ll*ifac[i-1]*inv[i]%mod;
}
int cmp(int x,int y) {return x>y;}
int c(int x,int y) {return 1ll*fac[x]*ifac[y]%mod*ifac[x-y]%mod;}
int main() {
read(n);for(int i=1,x;i<=n;i++) read(x),t[x]++;
prepare();sort(t+1,t+n+1,cmp);int cnt=0;
for(int i=1;i<=n+1;i++) if(!t[i]) {cnt=i-1;break;}
f[0][0]=1;
for(int i=1;i<=cnt;i++) s[i]=s[i-1]+t[i];
for(int i=1;i<=cnt;i++)
for(int j=0;j<=s[i];j++)
for(int k=0;k<=j&&k<=t[i];k++)
f[i][j]=(f[i][j]+1ll*f[i-1][j-k]*c(t[i],k)%mod*fac[t[i]]%mod*ifac[t[i]-k]%mod)%mod;
int ans=0;
for(int i=0,p=1;i<=n;i++,p=-p) ans=(ans+1ll*fac[n-i]*p*f[cnt][i]%mod)%mod;
for(int i=1;i<=cnt;i++) ans=1ll*ans*ifac[t[i]]%mod;
write((ans+mod)%mod);
return 0;
}