首先把所有数都转换成二进制,然后可以对二进制的每一位分别来计算异或和,假设第i位N个数中有a个是1,b个是0,那么只有选奇数个1时异或和是1,选偶数个时异或和就是零。
所以就是在a个数中挑1,3,5...K个数,b个数中挑K-1,K-3......个0的方案数,这个数可以用组合数算出来。再用这个数乘上这一位2进制的权值(1<<i)就是这一位产生的方案的和,注意会爆int。
还有一个坑点是在预处理组合数时,要用C[N][K]=C[N-1][K]+C[N-1][K-1]这个公式算,否则用乘法公式算的时候mod之后再除可能会取整了。这里wa了N次。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define LL long long
#define mod (1000003)
int a[100];
int N;
LL c[1005][1005];
void get(int n){
int pos=1;
while(n){
if(n&1) a[pos]++;
n>>=1;
pos++;
}
}
int main(){
memset(c,0,sizeof(c));
c[0][0]=1;
c[1][0]=1;
c[1][1]=1;
for(int i=2;i<=1000;i++){
c[i][0]=1;
for(int j=1;j<=i;j++){
c[i][j]=c[i-1][j]+c[i-1][j-1];
c[i][j]%=mod;
}
}
while(~scanf("%d",&N)){
memset(a,0,sizeof(a));
for(int i=1;i<=N;i++){
LL tmp;
scanf("%I64d",&tmp);
get(tmp);
}
LL res=0;
for(int i=1;i<=N;i++){
res=0;
for(int j=1;j<=80;j++){
if(!a[j]) continue;
for(int k=1;k<=a[j];k+=2){
if(k>i) break;
LL tmp=c[a[j]][k]*c[N-a[j]][i-k];
tmp%=mod;
LL tmp2=(1<<(j-1));
tmp2%=mod;
tmp*=tmp2;
tmp%=mod;
res+=tmp;
res%=mod;
}
}
printf("%I64d",res);
if(i!=N) printf(" ");
else printf("\n");
}
}
return 0;
}