好难懂的一道题啊……%%%sillyf
先把题目转化一下,答案就等于所有组合-and值不为零的组合。
定义
f[x]
为
ai&x==x
的
ai
的个数,
g[x]
为
x
转化为二进制后1的个数。
容斥一下求and不为零的组合情况:
ans=∑x=11000000(−1)g[x]−1×(2f[x]−1)
2f[x]−1 是因为不能一个都不选。
最后用
2n−1
减一下:
ans=∑x=11000000(−1)g[x]×(2f[x]−1)
至于为什么式子变成这样,我也不知道……所以就用第一的式子打了。
p.s.这题是双倍经验啊,codeforces 449D是一道一模一样的题目。
附上AC代码:
#include <cstdio>
#include <cctype>
#include <cstring>
using namespace std;
const int N=1e6+10,mod=1e9+7;
int n,pow[21],g[N],x,f[N],ans;
inline char nc(void){
static char ch[100010],*p1=ch,*p2=ch;
return p1==p2&&(p2=(p1=ch)+fread(ch,1,100010,stdin),p1==p2)?EOF:*p1++;
}
inline bool read(int &a){
static char c=nc();int f=1;
for (;!isdigit(c);c=nc()){
if (c==EOF) return 0;
if (c=='-') f=-1;
}
for (a=0;isdigit(c);a=(a<<3)+(a<<1)+c-'0',c=nc());
return a*=f,1;
}
inline void print(int a){if (a/10) print(a/10);putchar(a%10+'0');}
inline long long ksm(long long x,int y){
long long ret=1;
while (y){
if (y&1) ret=1ll*ret*x%mod;
y>>=1,x=1ll*x*x%mod;
}
return ret;
}
int main(void){
pow[0]=1;
for (int i=1; i<=20; ++i) pow[i]=pow[i-1]<<1;
for (int i=1; i<=1e6; ++i)
for (int j=0; j<=20; ++j) g[i]+=(i&pow[j]?1:0);
while (read(n)){
memset(f,0,sizeof f),ans=0;
for (int i=1; i<=n; ++i) read(x),++f[x];
for (int i=20; i>=0; --i)
for (int j=0; j<=1e6; ++j)
if (j&pow[i]) f[j^pow[i]]+=f[j];
for (int i=1; i<=1e6; ++i) ans=(ans+(g[i]&1?1:-1)*(ksm(2,f[i])-1+mod)%mod+mod)%mod;
print((ksm(2,n)-ans-1+mod)%mod),putchar('\n');
}
return 0;
}