传送门
解析:
还是挺好想的,首先对于k=1的情况,如果某一个数在这一位上有1,那么最终结果中这一位为1的概率就是0.5。
有一个很显然的性质,所有异或结果出现概率(或者说方案数)相同。
其次,对于k=2的情况,线性基上高消,然后直接考虑每个二元组就行了。
对于剩下的,由于保证答案不超过 2 63 2^{63} 263,所以数本身不超过 2 21 2^{21} 221,直接暴力干就行了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
re char c;
while(!isdigit(c=gc()));re T num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int getint(){return get<int>();}
inline ull getull(){return get<ull>();}
}
using namespace IO;
using std::cerr;
using std::cout;
ull base[100],a[100005];
inline void ins(ull a){
for(int re i=0;i<=63;++i)if((1ull<<i)&a){
if(!base[i]){
base[i]=a;
return ;
}
a^=base[i];
}
}
int n,m,k;
ull ans1,ans2;
inline void dfs(int step,ull state){
if(step>m){
ll sum1=0,sum2=1;
for(int re i=1;i<=k;++i){
sum1*=state,sum2*=state;
sum1+=(sum2>>m);
sum2&=(1<<m)-1;
}
ans1+=sum1,ans2+=sum2;
ans1+=(ans2>>m);
ans2&=(1<<m)-1;
return ;
}
dfs(step+1,state);
dfs(step+1,state^base[step]);
}
signed main(){
n=getint(),k=getint();
if(k==1){
ull ans=0;
for(int re i=1;i<=n;++i)ans|=getull();
printf(ans&1?"%llu.5":"%llu",ans>>1);
return 0;
}
if(k==2){
m=1;
for(int re i=1;i<=n;++i)base[1]|=a[i]=getull();
for(int re i=1;i<=n;++i)
for(int re j=1;j<=m;++j){
if(!(base[j]&~a[i])||!(base[j]&a[i]))continue;
base[++m]=base[j]&a[i];base[j]&=~a[i];
}
ull ans=0;
for(int re i=1;i<=m;++i)
for(int re j=i;j<=m;++j)ans+=base[i]*base[j];
printf(ans&1?"%llu.5":"%llu",ans>>1);
return 0;
}
for(int re i=1;i<=n;++i)ins(getull());
m=0;
for(int re i=0;i<64;++i)if(base[i])base[m++]=base[i];
for(int re i=m;i;--i)base[i]=base[i-1];
dfs(1,0);
printf(ans2?"%llu.5":"%llu",ans1);
return 0;
}