BZOJ - 4710 分特产

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


题解:
  首先我们要知道一个结论,把m相同的物品分给n个人的方案数是C(m+n-1,n-1),这个我们可以随便画上去m+n—1个求,其中选n-1个球,把整个序列划分成了n段,每一段就是每个盒子了球的个数,这样就简单证明了这个结论。
  然后,我们就可以统计出所有的方案数——∏(1~m)C(ai+n-1)(n-1)(ai是i号特产的数量)。得到这个我们也可以推出式子C(n,f)*∏(1~m)C(ai+n-f-1)(n-f-1)表示我们强制不选f个人,让他们一个都没有,也就是至少f个人一个都没有的方案数,记为f[i]。
  那么根据容斥,ans=f[0]-f[1]+f[2]-f[3]……,这样就统计出答案了。

代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#define MAXN 2100
#define mod 1000000007
#define ll long long
using namespace std;
ll c[MAXN][MAXN],a[MAXN];
ll ans=0;int n,m;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) scanf("%lld",&a[i]);
    c[1][0]=c[1][1]=1;
    for(int i=2;i<=2000;i++){
        c[i][0]=1;
        for(int j=1;j<=i;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
    }
    for(int i=0,f=1;i<=n;i++,f=-f){
        int now=c[n][i];
        for(int j=1;j<=m;j++)
            now=(now*c[a[j]+n-i-1][n-i-1])%mod;
        ans=(ans+now*f)%mod;
    }
    printf("%lld",(ans+mod)%mod);
    return 0;
}

 

posted @ 2017-09-26 16:25  人间失格—太宰治  阅读(238)  评论(0编辑  收藏  举报