Devu和鲜花 (容斥原理)

题目:

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

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

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

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

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

输入格式

第一行包含两个整数N和M。

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

输出格式

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

数据范围

1N201≤N≤20,
0M10140≤M≤1014,
0Ai10120≤Ai≤1012

输入样例:
3 5
1 3 2
输出样例:
3

解题报告:
一开始没有研究出来怎么容斥处理,后来参考了一下大佬的博客,才理解了这道题目的真谛!

首先假设如果所有的fi都没有限制的情况。
根据无限多重集合的组合数那么答案即为C(s,n+s−1) 
我们需要从这个答案中减去不合法的情况。
不合法的情况即为xi>fixi>fi的情况。
设AiAi为xi>fixi>fi的方案。
|Ai|=C(s−(fi+1),n+s−1−(fi+1))
相当于我们预先放好这fi+1fi+1个元素。
同理|Ai⋂Aj|=C(s−(fi+1)−(fj+1),n+s−1−(fi+1)−(fj+1))
根据容斥原理答案即为
C(s,n+s−1)−∑1≤i≤n|Ai|+∑1≤i<j≤n|Ai⋂Aj|−...(省略)

我们可以通过状态压缩表示每个状态。
预处理每个状态需要预先放好几个元素。
最后一遍扫描来统计答案。
时间复杂度O(2nn)

 

ac代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 
 5 const int mod=1e9+7;
 6 int n,lim;
 7 ll s,ans;
 8 ll f[30],inv[30],sum[1100000];
 9 int num[1100000];
10 ll comb(ll n,ll m)
11 {//求解C(n,m)   
12     if(m<0)
13         return 0;
14     ll ret=1;
15     for(ll i=m+1;i<=n;i++)
16         ret=ret*(i%mod)%mod;//n!/m!
17     for(int i=1;i<=n-m;i++)
18         ret=ret*inv[i]%mod;//(n-m)!
19     return ret;
20 }
21 
22 int main()
23 {
24     cin>>n>>s;//n个盒子,挑选s朵花 
25     for(int i=0;i<n;i++)
26         cin>>f[i];//输入n个盒子中的花朵数目 
27     inv[1]=1;
28     for(int i=2;i<=n+1;i++)
29         inv[i]=(inv[mod%i]*(mod-mod/i))%mod;//神奇的求解逆元打表 
30     lim=(1<<n)-1;//二进制枚举 ,便于容斥 
31     for(int i=0;i<=lim;i++)
32     {
33         for(int j=0;j<n;j++)
34         {
35             if(i&(1<<j))
36             {
37                 sum[i]+=f[j]+1;// 预先放好fi+1个元素 
38                 num[i]++;//标记一下出现的次数 
39             }
40         }
41     }//已经处理好了所有的状态,从1,2,--> n 
42     for(int i=0;i<=lim;i++)
43     {
44         if(num[i]%2)
45             ans=(ans-comb(s+n-1-sum[i],s-sum[i])+mod)%mod;
46         else
47             ans=(ans+comb(s+n-1-sum[i],s-sum[i]))%mod;
48     }
49     cout<<ans<<endl;
50 } 

 



转载于:https://www.cnblogs.com/Spring-Onion/p/11310470.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值