不得不说这题的确挺苟的。
注:下述“引理”表示:
对于长度为 \(n\) 的数组 \(V\),其线性基为 \(B\),定义 \(c_v=\bigoplus\limits_{a\in v}a\),\(num_k=\sum\limits_{v\subseteq V}[c_v=k]\),则 \(\forall k\in\mathbb{N},num_k\in\{0,2^{n-|B|}\}\)。
对于 \(k=1\) 的情况,容易想到按位分类,所有能取到的二进制位,最终的异或和中为 \(1\) 的概率都为 \(\frac 12\),证明相当于是杨辉三角的一行,奇数位之和和偶数位之和相等,很容易证明。这一部分时间复杂度 \(O(n+\log V)\)。
对于 \(k=2\) 的情况,根据 \((a+b)^2=a^2+b^2+2ab\),考虑拆成 \(a^2\) 和 \(ab\) 两部分考虑。\(a^2\) 和原先处理方法一样,\(ab\) 的概率为 \((\frac 12)^2=\frac 14\)。但是假如在所有 \(a_i\) 中,这两位都是同时出现或同时消失,那么就还是 \(\frac 12\)。时间复杂度 \(O(n+\log^2 V)\)。
接下来的部分可以继续这样推下去,但是 我觉得再推下去我就要死了,所以考虑暴力枚举所有可能值。根据引理,可得所有出现过的异或和出现次数都一样,问题转化为所有可能的异或和求和。由于实际上 \(V=\sqrt[k]{V'}\),所以当 \(k>2\) 时,\(V\le 2^{22}\),那么直接建立线性基后暴力搜索即可。时间复杂度 \(O(n+V)\)。
实际上,根据 \(k=1,2\) 的情况,容易证明 \(\{ans\}\in\{0,0.5\}\),所以只需要在计算答案时整体 \(\times 2\),输出时特判即可避免小数运算。
#include<bits/stdc++.h>
#define int unsigned long long
#define iint __int128
using namespace std;
const int N=1e5+5,M=65;
int n,k,ans,a[N],fl[M][M];
int p[M],fg[M];iint sm;
void add(int x){for(int i=30;~i;i--)if(x&(1ull<<i)){if(p[i]) x^=p[i];else{p[i]=x;return;}}
}iint pp(int x){iint re=1;for(int i=0;i<k;i++) re*=x;return re;
}iint sum(int nw,int x){if(nw+1==0) return sm++,pp(x);if(!p[nw]) return sum(nw-1,x);iint re=sum(nw-1,x^p[nw]);return re+sum(nw-1,x);
}void solve1(){for(int i=1;i<64;i++)if(fg[i]) ans+=(1ull<<(i-1));cout<<ans<<(fg[0]?".5":"");
}void solve2(){for(int i=0;i<33;i++)for(int j=i+1;j<33;j++) fl[i][j]=1;for(int i=1;i<=n;i++)for(int j=0;j<33;j++) for(int l=j+1;l<33;l++)fl[j][l]&=(((a[i]>>j)&1)==((a[i]>>l)&1));for(int i=0;i<33;i++){if(!fg[i]) continue;for(int j=i+1;j<33;j++){if(!fg[j]) continue;ans+=(1ull<<(i+j+fl[i][j]));}ans+=(1ull<<(2*i));}cout<<ans/2<<(ans%2?".5":"");
}void solve3(){iint cc=sum(30,0)*2;ans=(int)(cc/sm);cout<<ans/2<<(ans%2?".5":"");
}signed main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);cin>>n>>k;for(int i=1;i<=n;i++){cin>>a[i],add(a[i]);for(int j=0;j<64;j++)fg[j]|=((a[i]>>j)&1);}if(k==1) solve1();else if(k==2) solve2();else solve3();return 0;
}