[BZOJ4665] 小w的喜糖

[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}\binom{cnt_i}{k}cnt_i^{\underline{k}} \]

\(k\)是枚举当前糖不变的人数,我们先选出\(k\)个位置拿走,在任意地放回来,由于我们硬点了本质不同所以这玩意是对的。

由于原题中同色本质相同,所以每种情况都被算了\(\prod cnt_i!\),答案除掉就好了。

复杂度很好证明,我们的总枚举次数大概是:

\[\sum_{i=1}^{n}n\cdot 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('\n');}

#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;
}
posted @ 2019-06-19 20:52  Hyscere  阅读(504)  评论(0编辑  收藏  举报