bzoj 3811: 瑪裡苟斯【線性基+期望dp】
阿新 • • 發佈:2018-11-25
這個輸出可是有點噁心啊……WA*inf,最後抄了別人的輸出方法orz
還有注意會爆long long,要開unsigned long long
對於k==1,單獨考慮每一位i,如果這一位為1則有0.5的概率貢獻1<<i,否則沒有貢獻,因為這一位選了奇數偶數個1的概率是一樣的
對於k==2,考慮乘法的意義,也就是i位和j位同時為1的概率p,貢獻(1<<(i+j))*p,這個p,如果全部的a[k]都是在i位和j為相同則是p=0.5(因為這樣一來ij的值就關聯了),否則p=0.25
對於剩下的,建線性基後最多有21個元素,直接列舉所有狀態即可
#include<iostream> #include<cstdio> #include<cmath> using namespace std; const int N=100005; unsigned long long n,m,k,a[N],b[65],tot,ans,res; unsigned long long read() { unsigned long long r=0,f=1; char p=getchar(); while(p>'9'||p<'0') { if(p=='-') f=-1; p=getchar(); } while(p>='0'&&p<='9') { r=r*10+p-48; p=getchar(); } return r*f; } void ins(unsigned long long x) { for(int i=63;i>=0;i--) if(x>>i) { if(!b[i]) { b[i]=x; return; } x^=b[i]; } } int main() { n=read(),k=read(); for(int i=1;i<=n;i++) a[i]=read(); if(k==1) { for(int i=1;i<=n;i++) ans|=a[i]; printf("%llu",ans>>1),puts((ans&1)?".5":""); return 0; } if(k==2) { unsigned s=0; for(int i=1;i<=n;i++) s|=a[i]; for(int i=0;i<32;i++) for(int j=0,fl=0;j<32;++j,fl=0) if((s>>i&1)&&(s>>j&1)) { for(int k=1;k<=n;k++) if((a[k]>>i&1)^(a[k]>>j&1)) { fl=1; break; } if(i+j-1-fl<0) ++res; else ans+=1llu<<(i+j-1-fl); } ans+=res>>1; printf("%llu",ans),puts((res&1)?".5":""); return 0; } unsigned long long ans=0; for(int i=1;i<=n;i++) ins(a[i]); // for(int i=0;i<=20;i++) // cerr<<b[i]<<" ";cerr<<endl; for(m=22;!b[m];m--); m++; for(int s=0,len=(1<<m);s<len;s++) { unsigned long long sm=0,r=1; for(int i=0;i<m;i++) if(s&(1<<i)) sm^=b[i]; for(int i=1;i<k;i++) r*=sm; if(r<len) { r*=sm,tot+=r; if(tot>=len) ans+=tot/len,tot%=len; } else { ans+=r/len*sm,r%=len,r*=sm,tot+=r; if(tot>=len) ans+=tot/len,tot%=len; } } printf("%llu",ans),puts(tot?".5":""); return 0; }