BZOJ 3811: 玛里苟斯 线性基
https://www.lydsy.com/JudgeOnline/problem.php?id=3811
老夫线性基出师啦!(没有)
https://blog.sengxian.com/algorithms/linear-basis 感谢cydiater给的网址(我怎么不自己百度啊伸手党真恶心呸)
求期望,指数1直接每一位取一个二分之一就阔以了。
指数2可以两位两位结合然后取二分之一或者四分之一(把二维变成两个一维相乘,如果某两位每次都是一起出现,那么有贡献的概率就是1/2,如果有一次及以上不一起出现,有贡献的概率就是1/4),指数2这里我的代码在找某位的1存在的时候直接找的原数,找线性基更快,但是找两位的1是否一定一起出现只能用原数。
指数3以上的话线性基的位数就很少了可以直接搜,为了不爆ull有一个特殊的技巧(看代码)(因为最后要除2^位数那么把小于2^位数的存一下,大于2^位数的存一下)。
出现小数的话小数只能为.5,从指数1的情况可以推广。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 #define LL unsigned long long 8 const int maxn=100005; 9 int n,m,f=0,mx; 10 LL b[65]={},c[65]={},a[maxn]={}; 11 inline void init(LL x){ 12 for(int i=mx;i>0;i--){ 13 if(x&c[i]){ 14 if(!b[i]){ 15 for(int j=1;j<i;++j)if((x>>(j-1))&1)x^=b[j]; 16 for(int j=i+1;j<=60;++j)if((b[j]>>(i-1))&1)b[j]^=x; 17 b[i]=x;break; 18 } 19 x^=b[i]; 20 if(!x)f=1; 21 } 22 } 23 } 24 int main(){ 25 LL x,y; 26 scanf("%d%d",&n,&m); 27 c[1]=1; for(int i=2;i<=32;++i)c[i]=c[i-1]*2; 28 if(m==1){ 29 x=0; 30 for(int i=1;i<=n;++i){scanf("%llu",&y);x|=y;} 31 printf("%llu",x/2); 32 if(x&1)printf(".5"); 33 printf("\n"); 34 } 35 else if(m==2){ 36 LL ans=0,fla=0;mx=32; 37 for(int i=1;i<=n;++i){scanf("%llu",&a[i]);init(a[i]);} 38 for(int i=1;i<=mx;++i){ 39 for(int j=1;j<=mx;++j){ 40 bool f=0; 41 for(int k=1;k<=n;++k)if((a[k]>>(i-1))&1){f=1;break;} 42 if(!f)continue; 43 f=0; 44 for(int k=1;k<=n;++k)if((a[k]>>(j-1))&1){f=1;break;} 45 if(!f)continue; 46 f=0; 47 for(int k=1;k<=n;++k)if(((a[k]>>(i-1))&1)!=((a[k]>>(j-1))&1)){f=1;break;} 48 if(i==1&&j==1)fla++; 49 else if(((i==1&&j==2)||(i==2&&j==1))&&f)fla++; 50 else{ 51 if(f) ans+=((LL)1<<(i+j-4)); 52 else ans+=((LL)1<<(i+j-3)); 53 } 54 } 55 } 56 ans=ans+fla/2;printf("%llu",ans); 57 if(fla&1)printf(".5"); 58 printf("\n"); 59 } 60 else{ 61 LL ans=0,fla=0;int siz=0;mx=24; 62 for(int i=1;i<=n;++i){scanf("%llu",&x);init(x);} 63 for(int i=1;i<=mx;++i)if(b[i])b[++siz]=b[i]; 64 LL num=((LL)1<<siz); 65 for(LL i=1;i<num;++i){ 66 LL tem=0; 67 for(int j=0;j<siz;++j)if(i&((LL)1<<j))tem^=b[j+1]; 68 LL aa=0,bb=1; 69 for(int j=0;j<m;++j){ 70 aa*=tem;bb*=tem; 71 aa+=bb/num;bb&=(num-1); 72 } 73 ans+=aa;fla+=bb; 74 ans+=fla/num;fla&=(num-1); 75 } 76 printf("%llu",ans); 77 if(fla)printf(".5"); 78 printf("\n"); 79 } 80 return 0; 81 }