• CF449D Jzzhu and Numbers (状压DP+容斥)


    题目大意:

    给出一个长度为n的序列,构造出一个序列使得它们的位与和为0,求方案数

    也就是从序列里面选出一个非空子集使这些数按位与起来为0.

    看了好久才明白题解在干嘛,我们先要表示出两两组合位与和为0的所有情况

    先hx一下每个数出现的次数,然后我们从遍历 i ,i 是二进制的数位

    然后遍历所有的情况,如果第 i 位有1,那么说明我们去掉第 i 位的1就是又一种情况!

    其实我们统计的是所有数在删掉/不删掉每一位的1 所有可能出现的数!

    那么,状态内任意组合,不能取空集,把空集加上的话,会发现其实是二项式定理的展开,总数就是2^k -1

    仍然不是很理解,明天再思考思考

     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <cstring>
     4 #define ll long long
     5 #define N (1<<20)+100
     6 #define maxn 1000000
     7 #define mod 1000000007
     8 using namespace std;
     9 
    10 int n;
    11 int hx[N];
    12 ll xx,yy,tt;
    13 ll pw[N],sum[N],ans[22];
    14 void get_pw() {pw[0]=1;for(ll i=1;i<=n+1;i++) pw[i]=(pw[i-1]*(ll)2)%mod;}
    15 
    16 int main()
    17 {
    18     freopen("data.in","r",stdin);
    19     scanf("%d",&n);
    20     int x;
    21     for(int i=1;i<=n;i++) 
    22     {
    23         scanf("%d",&x);
    24         hx[x]++;
    25         sum[x]=hx[x];
    26     }
    27     for(int j=0;j<20;j++)
    28     {
    29         for(int s=(1<<20)-1;s>=0;s--)
    30             if(s&(1<<j)) sum[s^(1<<j)]+=sum[s]; 
    31     }
    32     get_pw();
    33     for(int s=0;s<(1<<20);s++)
    34     {
    35         int cnt=0;
    36         for(int j=0;j<20;j++)
    37             if(s&(1<<j))
    38                 cnt++;
    39         ans[cnt]+=((pw[sum[s]]-1)%mod+mod)%mod;
    40         ans[cnt]%=mod;
    41     }
    42     ll ret=0;
    43     for(int i=0;i<20;i++)
    44     {
    45         if(i&1) ret-=ans[i],ret%=mod;
    46         else    ret+=ans[i],ret%=mod;
    47     }
    48     printf("%lld\n",(ret%mod+mod)%mod);
    49     return 0;
    50 }
  • 相关阅读:
    浅谈MVP与ModelViewViewModel(MVVM)设计模式
    策略模式
    C#验证码
    如何招到烂程序员
    承载和使用WCF服务
    .NET Remoting 使用总结
    基于.Net Remoting的应用程序
    HTML5 是什么?
    关于HTTP及XMLHTTP状态代码一览
    Remoting多个信道(Chennel)的注册问题
  • 原文地址:https://www.cnblogs.com/guapisolo/p/9696988.html
Copyright © 2020-2023  润新知