题解 [BZOJ4710] 分特产
解析
step 1
我们先考虑下有人没有的情况吧,
那对于每个特产就是放隔板的情况了,
设\(a[i]\)为第\(i\)个特产的个数,
那么第\(i\)个特产的方案数就是\(C_{a[i]+n-1}^{n-1}\),(这个不解释了吧)
然后再根据乘法原理乘起来就行了:\(\prod_{i=1}^mC_{a[i]+n-1}^{n-1}\).
step 2
但是要求每个人都要分到啊.
而上面的式子是包含了有人没有的情况的.
所以我们容斥一下就好了.
设\(f[k]\)表示至少有\(k\)个人没有分到(也就是钦定\(k\)个人没有),
那么方案数就是\(f[k]=\prod_{i=1}^mC_{a[i]+n-k-1}^{n-k-1}\).
最后来一个容斥:\(ans=\sum_{k=0}^{n-1}(-1)^kC_n^kf[k]\),
组合数是因为可以任意钦定\(k\)个人没有.
code:
#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
#define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout)
using namespace std;
inline int read(){
int sum=0,f=1;char ch=getchar();
while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
return f*sum;
}
const int N=2001;
const int Mod=1000000007;
int n,m,a[N];
ll c[N][N];
ll f[N],ans;
int main(){
n=read();m=read();
for(int i=0;i<N;i++) c[i][0]=1;
for(int i=1;i<N;i++)
for(int j=1;j<N;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%Mod;
for(int i=1;i<=m;i++) a[i]=read();
for(int i=0;i<=n;i++) f[i]=1;
for(int i=0;i<n;i++)
for(int j=1;j<=m;j++) f[i]=(f[i]*c[a[j]+n-i-1][n-i-1])%Mod;
for(int i=0;i<n;i++) ans=(ans+c[n][i]*f[i]%Mod*((i&1)? -1:1))%Mod;
printf("%lld\n",(ans+Mod)%Mod);
return 0;
}