题目大意
有n个整数,问从他们中取出若干个数字相与之后结果是0的有多少组。
答案比较大,输出对于 1,000,000,007 (1e9+7)取模后的结果。
n,a[i]≤
106
分析
直接做无从下手,但是可以考虑下容斥。
设f[i]表示有多少个a[x],满足a[x]&i==i。
设g[i]表示i在二进制下有多少个1。
那么答案
Ans=∑(−1)g[i]∗2f[i]
现在问题在于求出f[]。
考虑使用分治:
当前分治区间为[l,l+
2k
)
那么
f[i]=f[i]+f[i+2k−1]|i∈[l,l+2k−1)|
然后再继续分下去。
正确性显然。
时间复杂度
O(220∗20)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1e6+5,M=1<<20,mo=1e9+7;
typedef long long LL;
int n,f[M],g[M],ans,p[M];
char c;
int read()
{
for (c=getchar();c<'0' || c>'9';c=getchar());
int x=c-48;
for (c=getchar();c>='0' && c<='9';c=getchar()) x=x*10+c-48;
return x;
}
void solve(int l,int r)
{
if (l==r) return;
int mid=l+r>>1,t=(r-l+1)/2;
for (int i=l;i<=mid;i++) f[i]=(f[i+t]+f[i])%mo;
solve(l,mid);
solve(mid+1,r);
}
int main()
{
n=read();
for (int i=0;i<n;i++) f[read()]++;
g[0]=1;
for (int i=1;i<M;i++) g[i]=g[i-(i&-i)]^1;
solve(0,M-1);
p[0]=1;
for (int i=1;i<=n;i++) p[i]=p[i-1]*2%mo;
for (int i=0;i<M;i++) if (g[i]) ans=(ans+p[f[i]])%mo;
else ans=(ans+mo-p[f[i]])%mo;
printf("%d\n",ans);
return 0;
}