[51nod1407]与与与与

  有n个整数,问从他们中取出若干个数字相与之后结果是0的有多少组。
  答案比较大,输出对于 1,000,000,007 (1e9+7)取模后的结果。

 Input
  第一行输入一个整数n。(1<=n<=1,000,000).
  第二行有n个整数a[0],a[1],a[2],...a[n-1],以空格分开.(0<=a[i]<=1,000,000)
 Output
  对于每一组数据,输出一个整数。

 

  又是没见过的姿势...

  如果对于每个数x都可以算出a[i]&x==x的数的个数的话就可以算了。

  f[i][j]表示 有多少个数 与j 得到的结果和j二进制表示下第i位到第20位相同(最低位为第0位),第0到i-1位都和j完全一样。

  初始化f[20][i]=读入的数组中等于i的数的个数。

  f[i][j]=

    f[i+1][j],j的第i位上是1

    f[i+1][j]+f[i+1][j+2^i],j的第i位上是0

  最后再容斥统计一波,ans=sum{ -1^num1 *f[0][i] }。i=0..2^20-1,num1是i二进制下1的个数

 

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 const int maxn=1052333,modd=1000000007;
 5 int f[maxn],a[maxn],two[maxn],n1[maxn];
 6 int i,j,k,n,m;
 7 
 8 int ra,fh;char rx;
 9 inline int read(){
10     rx=getchar(),ra=0,fh=1;
11     while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();
12     if(rx=='-')fh=-1,rx=getchar();
13     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra*fh;
14 }
15 inline void MOD(int &x){
16     if(x>=modd)x-=modd;else if(x<0)x+=modd;
17 }
18 int main(){
19     n=read();int mx=(1<<20)-1;register int i,j;
20     for(i=1;i<=n;i++)f[a[i]=read()]++;
21     for(i=two[0]=1;i<=n;i++)MOD(two[i]=two[i-1]<<1);
22     for(i=19;i>=0;i--)
23         for(j=0;j<=mx;j++)
24             if(!((j>>i)&1))f[j]+=f[j|(1<<i)];
25     int ans=0;
26     for(i=0;i<=mx;i++){//printf("i:%d  f:%d\n",i,f[i]);
27         n1[i]=n1[i>>1]+(i&1);
28         if(n1[i]&1)MOD(ans-=two[f[i]]);else MOD(ans+=two[f[i]]);
29     }
30     printf("%d\n",ans);
31 }
View Code

 

posted @ 2016-10-10 19:56  czllgzmzl  阅读(307)  评论(0编辑  收藏  举报