Codeforces 449D Jzzhu and Numbers

http://codeforces.com/problemset/problem/449/D

题意:给n个数,求and起来最后为0的集合方案数有多少

思路:考虑容斥,ans=(-1)^k*num(k),num(k)代表至少有k个数字and起来为1的方案数,那么怎么求num呢?

考虑and起来至少为x的方案数:那么一定是2^y-1,其中y代表有多少个数&x==x,问题就变成有多少数"包含"了某个数(二进制下),用dp解决这个问题:如果某一位数字是1,那么它一定能转移到它不是1的那个位置。

即:f[i]+=f[i|(1<<j)]

注意循环,如果两层的循环换一下位置就会重复计数了。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
const ll Mod=1000000007;
ll f[2000005],bin[2000005];
int n;
int read(){
    int t=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
    return t*f;
}
void solve(){
   for (int j=0;j<20;j++)
    for (int i=0;i<=1000000;i++)
        if ((1<<j)&i) (f[i^(1<<j)]+=f[i])%=Mod;
    ll ans=0;        
    for (int i=0;i<=1000000;i++){
        int cnt=1;
        for (int j=0;j<20;j++)
            if ((1<<j)&i) cnt=-cnt;
        ans=((ans+(cnt*(bin[f[i]]-1)%Mod))%Mod+Mod)%Mod;        
    }        
    printf("%I64d\n",ans);
}
int main(){
    n=read();
    bin[0]=1;
    for (int i=1;i<=1000000;i++) bin[i]=(bin[i-1]*2)%Mod;
    for (int i=1;i<=n;i++) f[read()]++;
    solve();
}

 

posted @ 2016-07-12 11:20  GFY  阅读(661)  评论(0编辑  收藏  举报