给你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(" "); } return 0; }