题意
给定可重集,求其子集的异或的 \(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;
}
标签:CTT,int,ll,中国国家队,llu,苟斯,printf,using,void
From: https://www.cnblogs.com/Yui-Hirasawa/p/18622259