博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

题解 [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;
}

posted @ 2019-07-13 20:00  Hastin  阅读(101)  评论(0编辑  收藏  举报