分三种情况讨论
k=1时,对于每一位而言,只要有一个数这一位是1,那么这个就有0.5的概率是1,选他就是1,不选就是0,有第二个的话,在第一个选或不选的前提下,也各有0.5的几率选或不选,0和1的概率还是一半一半。所以无论有几个,只要有任意一个数该位不得0,期望就是(1<<i)/2。所以我们只需要把所有的或起来除以二即可。
k=2时,我们需要记录每两位之间的贡献,如果所有的数这两位都一样而且有都是1的数,那么这两位作出的贡献就是(1<<i+j)/2,
如果有不一样的,那么贡献就是(1<<i+j)/4,
k>=3时,我们发现现在的异或和最大是(1<<22),因为题目保证答案在(1<<63)内,所以我们状压直接暴力乱搞就好了,因为线性基的期望就是原数组的期望。然而我并不会理性证明,只能感性理解
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 #include<vector> 7 #define LL unsigned long long 8 #define N 100500 9 using namespace std; 10 int n,m,p[66],bo[66]; 11 LL a[N],ANS,res; 12 vector<int> v; 13 int main(){ 14 scanf("%d%d",&n,&m); 15 for(int i=1;i<=n;i++)scanf("%llu",&a[i]); 16 if(m==1){ 17 LL ans=0; 18 for(int i=1;i<=n;i++)ans|=a[i]; 19 if(ans&1ll)printf("%llu.5\n",ans>>1ll); 20 else printf("%llu\n",ans>>1ll); 21 } 22 else if(m==2){ 23 LL ans=0; 24 for(int i=1;i<=n;i++)ans|=a[i]; 25 for(int i=0;i<=31;i++)if(ans&(1ll<<i))bo[i]=1; 26 for(int i=0;i<=31;i++)if(bo[i]){ 27 for(int j=0;j<=31;j++)if(bo[j]){ 28 bool flag=0; 29 for(int k=1;k<=n;k++)if(((a[k]>>i)&1)!=((a[k]>>j)&1)){flag=1;break;} 30 if(i+j-1-flag<0)res++; 31 else ANS+=1ll<<i+j-1-flag; 32 } 33 } 34 ANS+=res>>1ll;res&=1ll; 35 printf("%llu",ANS); 36 if(res)printf(".5\n"); 37 } 38 else{ 39 for(int i=1;i<=n;i++) 40 for(int j=23;~j;j--)if(a[i]&(1ll<<j)){ 41 if(p[j])a[i]^=a[p[j]]; 42 else{v.push_back(a[i]);p[j]=i;break;} 43 } 44 int nn=v.size(); 45 for(int i=0;i<(1<<nn);i++){ 46 LL val=0,a=0,b=1; 47 for(int j=0;j<nn;j++)if(i&(1<<j))val^=v[j]; 48 for(int j=1;j<=m;j++){ 49 a=a*val;b=b*val; 50 a+=(b>>nn);b&=(1ll<<nn)-1; 51 } 52 ANS+=a;res+=b; 53 ANS+=res>>nn;res&=(1ll<<nn)-1; 54 } 55 printf("%llu",ANS); 56 if(res)printf(".5\n"); 57 } 58 return 0; 59 }