bzoj4710 [Jsoi2011]分特产(容斥原理+组合数学)

题目要求有0个人有0个。
我们枚举有i个人有0个来容斥,其余的人随意分,用插板法来计算方案数。
A n s = i = 0 n 1 ( 1 ) i C n i j = 1 m C a j + n i 1 n i 1
复杂度 O ( n m )

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 1010
#define mod 1000000007
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,m,a[N],inv[N<<1],fac[N<<1],ans=0;
inline void inc(int &x,int y){x+=y;if(x>=mod) x-=mod;}
inline int C(int x,int y){
    return (ll)fac[x]*inv[y]%mod*inv[x-y]%mod;
}
int main(){
//  freopen("a.in","r",stdin);
    n=read();m=read();inv[0]=inv[1]=1;fac[0]=1;
    for(int i=1;i<=m;++i) a[i]=read();
    for(int i=2;i<=2000;++i) inv[i]=(ll)inv[mod%i]*(mod-mod/i)%mod;
    for(int i=1;i<=2000;++i) fac[i]=(ll)fac[i-1]*i%mod,inv[i]=(ll)inv[i-1]*inv[i]%mod;
    for(int i=0;i<n;++i){
        int res=C(n,i);
        for(int j=1;j<=m;++j) res=(ll)res*C(a[j]+n-i-1,n-i-1)%mod;
        inc(ans,(i&1)?mod-res:res);
    }printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/icefox_zhx/article/details/80741006