BZOJ 4710 分特产 容斥原理

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

分析:要直接算出每个人至少分到一个的总方案数显然是很困难的,于是考虑容斥,如果没有每人至少分一个的限制,不难看出总方案数为∏i(C[m+n-1][m-1]),如果有问题可以百度插板法。然后进行容斥,总方案数-至少有(n-1)个人分到的方案,+至少(n-2)个人分到的方案-……+/-至少0人分到的方案,故而可以求出结果。

# include <iostream>
# include <cstdio>
# include <cstring>
# include <cmath>
# include <list>
# include <map>
# include <queue>
# include <algorithm>
using namespace std;
typedef long long ll;
int read()
{
    int f=1,i=0;char ch=getchar();
    while(ch<'0'||ch>'9') 
    {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        i=(i<<3)+(i<<1)+ch-'0';
        ch=getchar();
    }
    return f*i;
}
const int mod=1e9+7;
ll C[2005][2005],a[1005];
int n,m;
ll ans;

int main()
{
    m=read(),n=read();
    for(int i=1;i<=n;++i) a[i]=read();
    for(int i=0;i<=2000;++i) C[i][0]=C[i][i]=1;
    for(int i=1;i<=2000;++i)
        for(int j=1;j<i;++j)
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
    int f;
    for(int i=0;i<m;++i)
    {
        if(i&1) f=-1;
        else f=1;
        ll now=1;
        for(int j=1;j<=n;++j)
            now=(ll)now*(C[a[j]+m-i-1][m-i-1])%mod;
        ans+=f*now*C[m][i]%mod;
    }
    cout<<(ans%mod+mod)%mod<<endl;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值