bzoj 4710
非常简单的组合数学+容斥原理
直接计算不好计算,我们用容斥原理计算:所有人随便选-至少有一个人没有礼物+至少有两个人没有礼物...
假设我们有$i$个人没有礼物,那么方案数为$C_{n}^{i}\prod_{j=1}^{m}C_{a[j]+n-i-1}^{n-i-1}$
后面那个组合数的含义是对于每一种特产,这种特产共有$a[j]$个,将其分给$n-i$个人,允许有人拿不到的方案数
可以理解成共有$a[j]+n-i-1$个位置,在其中插入$n-i-1$个隔板的方案数
因此总答案即为$\sum_{i=0}^{n}(-1)^{i}C_{n}^{i}\prod_{j=1}^{m}C_{a[j]+n-i-1}^{n-i-1}$
贴代码:
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <queue> #include <stack> #define ll long long using namespace std; const ll mode=1000000007; ll n,m; ll mul[1000005]; ll inv[1000005]; ll minv[1000005]; ll a[1000005]; void init() { inv[0]=inv[1]=minv[0]=minv[1]=mul[0]=mul[1]=1; for(int i=2;i<=1000000;i++) { inv[i]=(mode-mode/i)*inv[mode%i]%mode; mul[i]=mul[i-1]*i%mode; minv[i]=minv[i-1]*inv[i]%mode; } } ll C(ll x,ll y) { if(x<=y)return 0; return mul[x]*minv[y]%mode*minv[x-y]%mode; } int main() { scanf("%lld%lld",&n,&m); init(); for(int i=1;i<=m;i++)scanf("%lld",&a[i]); ll ans=0,f=1; for(int i=0;i<=n;i++) { ll sum=1; for(int j=1;j<=m;j++)sum=(sum*C(a[j]+n-i-1,n-i-1))%mode; ans=((ans+f*C(n,i)%mode*sum%mode)%mode+mode)%mode; f=-f; } printf("%lld\n",ans); return 0; }