BSOJ 2414 -- 【JSOI2011】分特产

Description

JYY 带队参加了若干场ACM/ICPC 比赛,带回了许多土特产,要分给实验室的同学们。
JYY 想知道,把这些特产分给N 个同学,一共有多少种不同的分法?当然,JYY 不希望任何一个同学因为没有拿到特产而感到失落,所以每个同学都必须至少分得一个特产。
例如,JYY 带来了2 袋麻花和1 袋包子,分给A 和B 两位同学,那么共有4 种不同的
分配方法:
A:麻花,B:麻花、包子
A:麻花、麻花,B:包子
A:包子,B:麻花、麻花
A:麻花、包子,B:麻花

Input

输入数据第一行是同学的数量N 和特产的数量M。
第二行包含M 个整数,表示每一种特产的数量。
N, M 不超过1000,每一种特产的数量不超过1000.

Output

输出一行,不同分配方案的总数。由于输出结果可能非常巨大,你只需要输出最终结果
MOD 1,000,000,007 的数值就可以了。

Sample Input

5 4 1 3 3 5

Sample Output

384835

 

首先,如果没有“每个人至少拿一个”的限制,那么答案就用经典的插板法解决。ans=\prod _{1\leqslant i\leqslant m}C_{w[i]+n-1}^{n-1}

然后我们肯定要容斥一下。还是老套路,我们要-{至少有一个人没有特产的方案}+{至少有两个人没有特产的方案}-{至少有三个人没有特产的方案}...

考虑求至少k个人没拿到特产的方案。首先我们要枚举哪k个人没拿到特产,然后再将所有特产分给剩下的n-k个人。所以方案数就是C_{n}^{k}\cdot \prod _{1 \leqslant i \leqslant m}C_{w[i]+n-k-1}^{n-k-1}

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<ctime>
#define ll long long
#define mod 1000000007ll

using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}

int n,m;
int w[1005];
ll f[1005],g[1005];
ll c[2005][2005],s,ans,tot[1005];
int main() {
	n=Get(),m=Get();
	c[0][0]=1;
	for(int i=1;i<=2000;i++)
		for(int j=0;j<=i;j++)
			c[i][j]=(!j||i==j)?1:(c[i-1][j-1]+c[i-1][j])%mod;
	for(int i=1;i<=m;i++) w[i]=Get();
	for(int i=1;i<=n;i++) {
		tot[i]=1;
		for(int j=1;j<=m;j++) {
			tot[i]=tot[i]*c[w[j]+i-1][i-1]%mod;
		}
	}
	int flag=1;
	for(int i=n;i>=1;i--) {
		ans=(ans+flag*c[n][i]*tot[i]%mod+mod)%mod;
		flag*=-1;
	}
	cout<<ans;
	return 0;
}

 

posted @ 2018-09-27 22:22  hec0411  阅读(159)  评论(0编辑  收藏  举报