hdu4810 <Cn中取i异或和>

来源:互联网 发布:excel拆分数据 编辑:程序博客网 时间:2024/06/07 10:55
题意:
     给你n个数,让你输出n个数,没一次输出的是在这n个数里面取i个数异或的和(所有情况<C n中取i>)。

思路:
     首先把所有的数都拆成二进制,然后把他们在某一位上的数字加起来,比如        3 = 11  5 = 101 他俩合并就是 112 就这样吧所有的数都合并了,一共最多32位,然后我们考虑,对于每一位,只有选择奇数个1的时候才会是1,否则就是0 ,所以我们可以一次枚举每一位,比如当前要取6个数,对于第三位有8个1,那么当前的这位就是
     C[8][1] * C[N-8][6-1] * 2^3 
  + C[8][3] * C[N-8][6-3] * 2^3 
  + C[8][5] * C[N-8][6-5] * 2^3

其中变化的那个1 3 5 就是去奇数的情况,每一次取完奇数后乘以剩下的的(6 - 奇数)的情况就是一共有多上中取当前奇数的情况 然后在乘以对应位上产生的数 2^3加在一起就是当要求取6个的时候在第三位上的8个1能产生的价值。

#include<stdio.h>#include<string.h>#define N 1005__int64 C[N][N];__int64 A[40] ,B[40];__int64 mod = 1000003;void DB_C(){   C[0][0] = C[1][0] = C[1][1] = B[1] = 1;   for(int i = 2 ;i <= 35 ;i ++)   B[i] = B[i-1] * 2 % mod;   for(int i = 2 ;i <= 1002 ;i ++)   {      C[i][0] = 1;      for(int j = 1 ;j <= i ;j ++)      C[i][j] = (C[i-1][j] + C[i-1][j-1]) % mod;   }   return ;}int main (){   int n ,i ,j ,k ,num;   DB_C();   while(~scanf("%d" ,&n))   {      memset(A ,0 ,sizeof(A));      for(i = 1 ;i <= n ;i ++)      {         scanf("%d" ,&num);         int tt = 0;         while(num)         {            A[++tt] += (num&1);            num /= 2;         }      }      for(i = 1 ;i <= n ;i ++)      {         __int64 ans = 0;         for(j = 1 ;j <= 32 ;j ++)         {            for(k = 1 ;k <= A[j] && k <= i ;k += 2)            {               if(i - k > n - A[j]) continue;               __int64 tmp = C[A[j]][k] * C[n - A[j]][i - k] % mod;               ans = (ans + tmp * B[j]) % mod;            }         }         if(i == 1) printf("%I64d" ,ans);         else printf(" %I64d" ,ans);      }      printf("\n");   }   return 0;}                              

0 0
原创粉丝点击