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(); }