容斥原理——Devu和鲜花

Devu和鲜花

Devu有N个盒子,第i个盒子中有Ai枝花。

同一个盒子内的花颜色相同,不同盒子内的花颜色不同。

Devu要从这些盒子中选出M枝花组成一束,求共有多少种方案。

若两束花每种颜色的花的数量都相同,则认为这两束花是相同的方案。

结果需对109+7取模之后方可输出。

输入格式
第一行包含两个整数N和M。

第二行包含N个空格隔开的整数,表示A1,A2,…,AN。

输出格式
输出一个整数,表示方案数量对109+7取模后的结果。

数据范围
1 ≤ N ≤ 20 1≤N≤20 1N20,
0 ≤ M ≤ 1 0 14 0≤M≤10^{14} 0M1014,
0 ≤ A i ≤ 1 0 12 0≤Ai≤10^{12} 0Ai1012
输入样例:
3 5
1 3 2
输出样例:
3

题解:

这道题如果没有限制,那么我们就是x元一次方程求解(根据题目中的背景我们需要保证每个未知数是正整数,所以我们两边同时加上一个N),也就是隔板法可以做。这里加了限制,所以我们可以用所有合法的情况减去所有不合法的情况的并集合。
根据容斥原理展开,我们就可以算了。因为N比较小所以容斥原理 2 n 2^n 2n可以满足。
不合法情况怎么判断昵?比如我们没有限制就是每个盒子有无穷支花,但是其实只有a个,所以我们拿a+1支花就不合法了。意思是每个盒子拿容量+1支花就不合法了。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 20, mod = 1e9 + 7;
int A[N],down=1;
int q_pow(int a, int k)
{
    int res = 1;
    while (k)
    {
        if (k & 1) res = res * a % mod;
        a = a * a % mod;
        k >>= 1;
    }
    return res;
}
int C(int a, int b)
{
    if (a < b) return 0;
    int up = 1;
    for (int i = a; i > a - b; i -- ) up = i % mod * up % mod;

    return (int)up * down % mod; // 费马小定理
}
signed main()
{
    int n,m; cin>>n>>m;
    for(int i=0;i<n;i++) scanf("%lld",A+i);
    int res=0;
    for(int i=1;i<=n-1;i++) down=i*down%mod;
    down=q_pow(down,mod-2);
    for(int i=0;i<(1<<n);i++){
        int a=n+m-1,b=n-1;
        int fuhao=1;
        for(int j=0;j<n;j++){
            if(i>>j&1){
                a-=A[j]+1;
                fuhao*=-1;
            }
        }
        res=(res+C(a,b)*fuhao)%mod;
    }
    cout<<(res+mod)%mod<<endl;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值