【题解】分特产(组合数+容斥)

【题解】分特产(组合数+容斥)

一道小水题。

假如没有这个要求每个人都要有一个特产的限制我们直接可以组合数。

我们又发现人(本质上)是没有区别的,所以容斥的复杂度只有\(O(n)\)

\(n\)个人分\(m\)个特产,每个特产有\(a_i\)个,人可以不拿特产,的方案数就是把\(a_i\)分成\(n\)份,而且可以分为\(0\)份。

这个的答案就是

\[f(n)=\prod_{i=1}^m {a_i+n-1\choose n-1} \]

意思就是有\(a_i+n\)个球分成不为空\(n\)份的方案,新建\(n\)个球,选了这\(n\)个球代表你不选。

于是我们就可以容斥出来我们要的答案。

\[\sum_{i=0}^{n-1} (-1)^if(n-i) \]

哦要解释一下这个式子的意思,\(f(x)\)里面的方案数包括了所有大于\(x>\)它的的方案数。我们才要容斥。

所以枚举钦定至少\(i\)个人一个也没有,最终我们要的是0个人一个也没有。

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define int long long

using namespace std;  typedef long long ll;
inline int qr(){
      register int ret=0,f=0;
      register char c=getchar();
      while(c<48||c>57)f|=c==45,c=getchar();
      while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
      return f?-ret:ret;
}
const int mod=1e9+7;
const int maxn=2e3+5;
int jc[maxn];
int inv[maxn];
int data[maxn];
inline int Pow(int base,const int&p){
      register int ret=1;
      for(register int t=p;t;t>>=1,base=1ll*base*base%mod)
	    if(t&1)ret=1ll*ret*base%mod;
      return ret;      
}

inline int c(const int&n,const int&m){
      if(n<m||m<0)return 0;
      return 1ll*jc[n]*inv[m]%mod*1ll*inv[n-m]%mod;
}

signed main(){

      jc[0]=inv[0]=1;
      for(register int t=1;t<maxn;++t)
	    jc[t]=1ll*jc[t-1]*t%mod,inv[t]=Pow(jc[t],mod-2);
      int n=qr(),m=qr();
      for(register int t=1;t<=m;++t)
	    data[t]=qr();
      int ans=0;
      for(register int t=0,delta;t<n;++t){
	    delta=c(n,t);
	    for(register int i=1;i<=m;++i)
		  delta=1ll*delta*c(data[i]+n-t-1,n-t-1)%mod;
	    if(t&1)delta=mod-delta;
	    ans=(ans+delta)%mod;
      }
      cout<<ans<<endl;      
      return 0;
}


posted @ 2019-06-13 16:50  谁是鸽王  阅读(242)  评论(0编辑  收藏  举报