传送门
题意简述:有
n
n
n个人,
m
m
m种物品,给出每种物品的数量
a
i
a_i
ai,问每个人至少分得一个物品的方案数(
n
,
m
,
每
种
物
品
数
≤
1000
n,m,每种物品数\le1000
n,m,每种物品数≤1000)。
思路:
我们算出
f
i
f_i
fi表示至少有
i
i
i个人没有分到物品的方案数容斥一下即可。
于是
f
i
=
C
n
i
∏
j
=
1
m
C
n
−
i
−
1
+
a
j
n
−
i
−
1
f_i=C_n^i\prod_{j=1}^mC_{n-i-1+a_j}^{n-i-1}
fi=Cni∏j=1mCn−i−1+ajn−i−1
前面的组合数指的是选出没有分到物品的
i
i
i个人,后面的指对于每一种物品分给剩下的
n
−
i
n-i
n−i个人的方案数。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
typedef long long ll;
const int N=2005,mod=1e9+7,mod1=1e9+6;
int ans=0,fac[N],ifac[N],n,m,a[N];
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(const int&a,const int&b){return a>=b?a-b:a-b+mod;}
inline int mul(const int&a,const int&b){return (ll)a*b%mod;}
inline int C(int n,int m){return mul(mul(fac[n],ifac[m]),ifac[n-m]);}
inline void init(){
fac[0]=ifac[0]=fac[1]=ifac[1]=1;
for(ri i=2;i<=2000;++i)fac[i]=mul(fac[i-1],i),ifac[i]=mul(ifac[mod-mod/i*i],mod-mod/i);
for(ri i=2;i<=2000;++i)ifac[i]=mul(ifac[i],ifac[i-1]);
}
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
int main(){
n=read(),m=read(),init();
for(ri i=1;i<=m;++i)a[i]=read();
for(ri tmp,i=0;i<=n;++i){
tmp=C(n,i);
for(ri j=1;j<=m;++j)tmp=mul(tmp,C(n-i-1+a[j],n-i-1));
ans=i&1?dec(ans,tmp):add(ans,tmp);
}
cout<<ans;
return 0;
}