题意
给定可重集,求其子集的异或的 \(k\) 次方和的期望。
$ |s| <= 10^5 , k \le 5 , 保证答案小于 2^{63} $。
分析
当 \(k=1\) 时,拆位算贡献即可。
当 \(k=2\) 时,同时考虑两位即可。
当 \(k \ge 3\),拆位不好计算,因为答案有上界 \(2^{63}\),所以 \(a_i<2^{21}\)。
断言:每种异或和出现次数相等。
考虑 \(A=\oplus a,B=\oplus b\) 其出现次数,设 \(C=A \oplus B\),对于每一个 \(X=A\) 都有与之对应的 \(Y=C^X\) 对应,得证。
构造线性基,暴力枚举子集计算答案即可,\(O(2^size)\)。
代码
#include <bits/stdc++.h>
#define lb(x) (x&-x)
using namespace std;
using ll=unsigned long long;
using LL=__int128;
using pii=pair<int,int>;
const int N=1e5+5;
ll n,k,v,a[N],p[21],c,t[21];
inline LL P(LL s,ll k){ return s*s*s*(k&4?k&1?s*s:s:1); }
void solve0(){for(int i=1;i<=n;i++)for(int j=20;~j;j--)if(a[i]>>j&1)if(!p[j]){ p[j]=a[i]; break; }else a[i]^=p[j];for(int i=20;~i;i--) p[i]?t[c++]=p[i]:0;__int128 w=0;for(int i=0;i<(1<<c);i++){ll s=0; for(int j=0;j<c;j++)if(i>>j&1) s^=t[j]; w+=P(s,k);} (w>>=c-1)&1?printf("%llu.5",w>>1):printf("%llu",w>>1);
}
void solve1(){ v&1?printf("%llu.5",v>>1):printf("%llu",v>>1); }
void solve2(){ ll s=0;for(int i=0;i<32;i++)for(int j=i+1;j<32;j++)if((v>>i&1)&&(v>>j&1))s+=1ll<<i+j;v&1?printf("%llu.5",(v>>1)+s):printf("%llu",(v>>1)+s);
}
int main(){scanf("%llu%llu",&n,&k);for(int i=1;i<=n;i++)scanf("%llu",a+i),v|=a[i];if(k==1) solve1();else if(k==2) solve2();else solve0(); return 0;
}