• 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 }
  • 相关阅读:
    CDN使用心得
    IIS6.0实现SSL安全加密
    从print css谈样式表的媒介(media)属性
    ASP.NET文件下载各种方式比较:对性能的影响、对大文件的支持、对断点续传和多线程下载的支持
    “同名Cookie”的分析
    周末部门游玩顺德碧桂园度假村
    Linux特殊文件权限
    周末部门游玩广州长隆欢乐世界
    开个博客
    iOS TableView数据绑定的原则
  • 原文地址:https://www.cnblogs.com/guapisolo/p/9696988.html
Copyright © 2020-2023  润新知