【bzoj4710】[Jsoi2011]分特产

JYY 带队参加了若干场ACM/ICPC 比赛,带回了许多土特产,要分给实验室的同学们。

JYY 想知道,把这些特产分给N 个同学,一共有多少种不同的分法?当然,JYY 不希望任何一个同学因为没有拿到特产而感到失落,所以每个同学都必须至少分得一个特产。
例如,JYY 带来了2 袋麻花和1 袋包子,分给A 和B 两位同学,那么共有4 种不同的分配方法:
A:麻花,B:麻花、包子
A:麻花、麻花,B:包子
A:包子,B:麻花、麻花
A:麻花、包子,B:麻花
输入

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

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

由于“每个同学都必须至少分得一个特产”这个限制比较难处理,所以我们可以考虑容斥,
用没有限制-至少1个人没分到+至少2个人没分到-... 得到答案。
考虑如果i个人没分到该怎么处理:n个人选出i个不分,方案数为C(n,i);
对于每种特产设有w[i]个,分给(n−i)个同学,允许有人拿不到,方案数为
c(w[i]+n-i-1,n-i-1)
故最终答案为∑(-1)^i * C(n,i) *∑C(w[j]+n-i-1,n-i-1) (0<=i<=n-1,1<=j<=m)
手动算一下
3 2
3 4
则没有限制的有c(3,0)*c(5,2)*C(6,2)=150
至少有一个人没拿到C(3,1)*C(4,1)*C(5,1)=60
至少有二个人没拿到C(3,2)*1*1=3
ans=150-60+3=93

#include <bits/stdc++.h>
#define N 2010
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
ll c[N][N];
int w[N];
int main()
{
    int n , m , i , j;
    ll ans = 0 , tmp;
    for(i = 0 ; i <= 2000 ; i ++ )
    {
        c[i][0] = 1;
        for(j = 1 ; j <= i ; j ++ )
            c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;
    }
    scanf("%d%d" , &n , &m);
    for(i = 1 ; i <= m ; i ++ )  //M个特产 
	      scanf("%d" , &w[i]);
    for(i = 0 ; i < n ; i ++ )
    {
        tmp = c[n][i];
       // cout<<" i is   "<<i<<endl;
        for(j = 1 ; j <= m ; j ++ )
        {
            tmp = tmp * c[ w[j] + n - i - 1] [w[j]] % mod;
	      //  cout<<" m iss   "<<c[ w[j] + n - i - 1] [w[j]]<<endl;
		}
	//	cout<<i<<" tmp is    "<<tmp<<endl;
        if(i & 1) 
		    ans = (ans - tmp + mod) % mod;
        else 
		    ans = (ans + tmp) % mod;
	//	cout<<i<<"  ans is   "<<ans<<endl;
    }
    printf("%lld\n" , ans);
    return 0;
}

  

上一篇:「JSOI2011」汇总


下一篇:BZOJ4710 [Jsoi2011]分特产 容斥