原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ62.html
题解
太久没更博客了,该拯救我的博客了。
按照 $k$ 分类讨论:
k=1 : 我们考虑每一位的贡献。若有至少一个数第 $i$ 位为 $1$ ,则对答案的贡献为 $2^i/2$ 。
k=2 : 发现每个异或和的平方为 $\sum_i\sum_j2^{i+j}bit_ibit_j$。那么考虑第 $i$ 位和第 $j$ 位的积的期望值。如果所有的数中,第 $i$ 位和第 $j$ 位均相等且非全零,那么参考 k=1 的情况,期望为 1/2;否则,第 $i$ 位为 $1$ 的概率为 1/2,第 $j$ 位为 $1$ 的概率为 1/2,$i×j$ 为 $1$ 的概率为 0.25 。
$k\leq 3$ : 由于答案不超过 $2^{63}$ ,直接把线性基搞出来之后暴力枚举就好了。
代码
#include <bits/stdc++.h> using namespace std; typedef unsigned long long ULL; const int N=100005; int n,k; ULL a[N]; void init(){ static ULL x[64],v; memset(x,0,sizeof x); cin >> n >> k; for (int i=1;i<=n;i++){ cin >> v; for (int i=63;~i;i--) if (v>>i&1ULL) if (!x[i]){ x[i]=v; break; } else v^=x[i]; } n=0; for (int i=63;~i;i--) if (x[i]) a[++n]=x[i]; } void Out(ULL x){ cout << x/2; if (x&1LLU) cout << ".5"; } namespace k1{ void solve(){ ULL ans=0; for (int i=1;i<=n;i++) ans|=a[i]; Out(ans); } } namespace k2{ void solve(){ ULL ans=0; for (int i=0;i<33;i++) for (int j=0;j<33;j++){ int f1=0,f2=0,f=0; for (int t=1;t<=n;t++){ f1|=a[t]>>i&1ULL; f2|=a[t]>>j&1ULL; f|=(a[t]>>i&1ULL)!=(a[t]>>j&1ULL); } if (!f1||!f2) continue; // cout << i << " " << j << " " << (1ULL<<(i+j+f)) << endl; ans+=1ULL<<(i+j-f); } cout << ans/2; if (ans%2) cout << ".5"; } } namespace k3{ __int128 tot; __int128 Pow(__int128 x,int y){ __int128 ans=1; for (;y;y>>=1,x*=x) if (y&1) ans*=x; return ans; } void solve(){ tot=0; for (int i=(1<<n)-1;i>=0;i--){ ULL tmp=0; for (int j=0;j<n;j++) if (i>>j&1) tmp^=a[j+1]; tot+=Pow(tmp,k); } while (tot%2==0&&n>1) n--,tot/=2; cout << (ULL)tot/2; if (tot%2==1) cout << ".5"; } } int main(){ init(); if (k==1) k1 :: solve(); else if (k==2) k2 :: solve(); else k3 :: solve(); return 0; }