zoukankan      html  css  js  c++  java
  • 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 } 


  • 相关阅读:
    tp3.2和tp5的区别
    tp(调试模式,空操作,跨控制器调用,跨方法跳转--redirect(),框架语法,创建model模型)
    tp 连表查 分页 模糊查询
    thinkphp if和eq的区别
    js 面向对象例子
    JS字符串转换为JSON的四种方法笔记
    json在php中的使用之如何转换json为数组
    window.frames用法
    php js 数组排序
    控件常用
  • 原文地址:https://www.cnblogs.com/Spring-Onion/p/11310470.html
Copyright © 2011-2022 走看看