bzoj3811 玛里苟斯

分三种情况讨论

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 }
View Code

 

posted @ 2018-01-29 20:26  Ren_Ivan  阅读(206)  评论(0编辑  收藏  举报