【BZOJ 3811】玛里苟斯 大力观察+期望概率dp+线性基
大力观察:I.从输出精准位数的约束来观察,一定会有猫腻,然后仔细想一想,就会发现输出的时候小数点后面不是.5就是没有 II.从最后答案小于2^63可以看出当k大于等于3的时候就可以直接搜索了
期望概率dp:对于k=1的时候,把所有存在的位乘0.5就行了,对于k=2的时候就可以用类似推反演的方法(转换枚举顺序之类的)退出来一个式子,然后你只需要求个概率(很好推,也很好求)就可以啦
线性基:搜索之前还有dp之前预处理用的(只是构造一下)
然而我的做法却是,先求出线性基,再用期望概率dp(类似OSU!那种).所以呢,我先被卡了几次精,后来有了zyf的提示,我才把double换成unsigned long long.之后又是一直wa,然后我发现,对于线性基,即使进行了向上消的操作(这个操作还不是很熟额),每一位也会有多个基为1.发现自己十分native......之后就懵逼了......又经过思考我把所有存在的位出现的概率都看作是0.5,并且相互独立,然后得到了76分,十分开心,我以为找到了正确的方向......结果最后发现,位与位之间的概率并不独立......但是这个东西在k=1的时候显然没用影响,在k>1的时候会有影响,但是k=2的时候,可以从正解的式子看出,造成的影响可以在你合并了所有在基上分布相同的位之后被消除,然而k>2的时候就复杂得多(至少我没想出来我的dp怎么继续做......)......所以最后还是特判了k>2的点用搜索跑过了......
从一开始我就由于没有观察题目性质和对线性基的误导把思路放到神奇的期望概率dp上,最后卡了很久,所以说我对线性基的理解和画柿子的思路以及对期望概率里样本空间的理解(或者说对独立事件的理解)还是很native(当然还有大力观察的能力)
#include <cstdio> #include <cstring> #include <algorithm> typedef unsigned long long LL; char xB[(1<<15)+10],*xS=xB,*xT=xB; #define gtc (xS==xT&&(xT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xT)?0:*xS++) inline void read(int &x){ register char ch=gtc; for(x=0;ch<'0'||ch>'9';ch=gtc); for(;ch>='0'&&ch<='9';x=(x<<1)+(x<<3)+ch-'0',ch=gtc); } inline void Read(LL &x){ register char ch=gtc; for(x=0;ch<'0'||ch>'9';ch=gtc); for(;ch>='0'&&ch<='9';x=(x<<1)+(x<<3)+ch-'0',ch=gtc); } int n,k,m,sum,cnt; LL x[6],c[6][6],pf[6],gay[64],temp,st[64],get,tot,val[64]; bool die[64]; #define bin(a,b) (((a)>>(b))&1) inline LL pick(LL key){ LL ret=key; for(int i=1;i<k;++i)ret*=key; return ret; } inline void dfs(int pos,LL have){ if(pos==m+1)return void(tot+=pick(have)); dfs(pos+1,have),dfs(pos+1,have^val[pos]); } int main(){ register int i,j;int l; for(read(n),read(k),i=1;i<=n;++i){ Read(temp); for(j=63;j>=0;--j){ if(!bin(temp,j))continue; if(gay[j])temp^=gay[j]; else{gay[j]=temp,++m;break;} } } for(i=63;i>=0;--i){ if(!gay[i])continue; for(j=i+1;j<=63;++j) if(bin(gay[j],i)) gay[j]^=gay[i]; } for(i=0;i<=63;++i) for(j=i;j<=63;++j) if(bin(gay[j],i)) st[i]|=((LL)1)<<j; for(i=0;i<=63;++i) if(gay[i]==0&&st[i])++sum; if(k>2&&sum&&m<10){ for(i=0;i<=63;++i) if(gay[i]) val[++cnt]=gay[i]; dfs(1,0),tot>>=m-1; long long tmp=tot>>1; if(tot&1)printf("%lld",tmp),puts(".5"); else printf("%lld\n",tmp); return 0; } c[0][0]=1; for(i=1;i<=k;++i){ c[i][0]=1; for(j=1;j<=i;++j) c[i][j]=c[i-1][j-1]+c[i-1][j]; } x[0]=2; for(i=0;i<=63;++i){ temp=0; for(j=0;j<=63;++j) if(bin(gay[j],i)){temp=1;break;} if(!temp)continue; temp=((LL)1)<<i; pf[0]=1; for(j=1;j<=k;++j)pf[j]=pf[j-1]*temp; for(j=k;j>0;--j) for(l=1;l<=j;++l) if(x[j-l]&1) x[j]+=x[j-l]*((c[j][l]&1)?(pf[l]>>1)*c[j][l]:(c[j][l]>>1)*pf[l]); else x[j]+=(x[j-l]>>1)*c[j][l]*pf[l]; } long long tmp=x[k]>>1; if(x[k]&1)printf("%lld",tmp),puts(".5"); else printf("%lld\n",tmp); return 0; }