【JSOI 2011】 分特产

【题目链接】

           点击打开链接

【算法】

           考虑求每个人可以不分的方案

           那么,对于每件物品,我们把它分成n份,每一份对应分给每一个人,有C(a[i]+n-1,m-1)种方案,而总方案数就是每种

           物品方案数的乘积

           然后,根据容斥原理,ans = 至少0人没分到特产 - 至少1人没分到特产 +  ... - C(m,m) * 没有一人分到

           特产

【代码】

            

#include<bits/stdc++.h>
using namespace std;
#define MAXN 2010
const long long P = 1000000007 ;

int i,n,m;
long long a[MAXN],fac[MAXN],inv[MAXN];
long long ans;

inline long long power(long long a,long long n)
{
	long long ans = 1,b = a;
	while (n > 0)
	{
		if (n & 1) ans = (ans * b) % P;
		b = (b * b) % P;
		n >>= 1;
	}
	return ans;
}
inline void init()
{
	int i;
	fac[0] = 1;
	for (i = 1; i < MAXN; i++) fac[i] = fac[i-1] * i % P;
	inv[MAXN-1] = power(fac[MAXN-1],P-2);
	for (i = MAXN - 2; i >= 1; i--) inv[i] = inv[i+1] * (i + 1) % P;
	inv[0] = 1;
}
inline long long C(int n,int m)
{
	return fac[n] * inv[n-m] % P * inv[m] % P;
}
inline long long calc(int x)
{
	int i;
	long long ans = 1;
	for (i = 1; i <= m; i++) ans = (ans * C(a[i]+n-x-1,n-x-1)) % P;
	return ans;	
}

int main()
{
	
	init();
	scanf("%d%d",&n,&m);
	for (i = 1; i <= m; i++) scanf("%d",&a[i]);
	for (i = 0; i <= n; i++)
	{
		if (i % 2 == 0) ans = (ans + C(n,i) * calc(i)) % P;
		else ans = (ans - (C(n,i) * calc(i) % P) + P) % P;
	}
	printf("%lld\n",ans);
	
	return 0;	
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值