雅禮 noip2018 模擬賽day3 T2
阿新 • • 發佈:2018-11-01
典型的狀壓思想
設0表示黑球,1表示白球,用一串01序列代表剩下的球的狀態,記f[i]表示在i狀態下取球的最大期望
那麼可以利用記憶化搜尋更新,每一層列舉可能拿走的球然後向下搜尋,同時記憶化即可
在狀態中刪去一個點可以利用位運算實現
同時要注意一個問題,就是狀態0010和狀態010並不是相同的狀態,但是如果不做處理在記憶化的過程中很可能把他倆算成相同的狀態,所以我們在初始狀態最前面放一個1,這樣就可以區分上述兩種狀態了
還有就是本題卡常卡的很厲害,所以對比較小的狀態我們用陣列,對過大的狀態再使用map來操作即可
注意使用double
#include <cstdio> #include <map> #define ll unsigned int using namespace std; const ll con=(1<<25)+(1<<23)+(1<<22); int n,k; char s[35]; double ret=0; int cct=0; map <ll,double> M; double f[con]; inline double max(double x,double y) { return x>y?x:y; } inline ll erase(ll sit,int pos) { ll temp=sit>>(pos-1); temp<<=(pos-1); ll ret=sit^temp; sit>>=pos; sit<<=(pos-1); ret|=sit; return ret; } inline int cot(ll sit) { int cyt=0; for(int i=0;i<n-k;i++) { if((1<<i)&sit) { cyt++; } } return cyt; } double dfs(int dep,ll sit) { if(sit<con&&f[sit]) { return f[sit]; }else if(M[sit]) { return M[sit]; } if(dep==k+1) { double tot=(double)cct-cot(sit); return tot; } double temp=0; for(int i=1;i<=n-dep+1;++i) { int ri=n+2-i-dep; double tt=0; tt=max(tt,dfs(dep+1,erase(sit,i))); tt=max(tt,dfs(dep+1,erase(sit,ri))); temp+=tt; } if(sit<con) { return f[sit]=temp/(double)(n-dep+1); }else { return M[sit]=temp/(double)(n-dep+1); } } int main() { freopen("v.in","r",stdin); freopen("v.out","w",stdout); scanf("%d%d",&n,&k); scanf("%s",s+1); ll ori=0; bool flag=0; for(int i=1;i<=n;++i) { if(s[i]=='W') { ori|=1; cct++; } if(s[i]!=s[i-1]&&i!=1) { flag=1; } ori<<=1; } if(k==0) { printf("0.000000000\n");; return 0; } if(k==n) { printf("%.10lf\n",(double)cct); return 0; } if(!flag) { if(s[1]=='W') { printf("%.10lf\n",(double)k); }else { printf("0.000000000\n"); } return 0; } ori>>=1; ori|=(1<<n); printf("%.10lf\n",(double)dfs(1,ori)); return 0; }