#数学期望,状压dp,记忆化搜索#nssl 1468 V


分析

赛时写了个\(O(n!)\)的纯暴力,其实我现在才发现\(O(n!)\)的暴力一般都能用\(O(n2^n)\)的状压dp解决
但是其实不是每个状态都能被访问到,所以若\(n\)过大,用\(map\)存,否则用数组存,还有记忆化搜索优化时间,反正能过


代码

#include <cstdio>
#include <map>
#define rr register
using namespace std;
const int N=31,M=24; int n,k,now;
struct either{
	double ku[(1<<M)|1];
	map<int,double>uk[N];
    inline void Init(){for (rr int i=0;i<=(1<<M);++i) ku[i]=-1;}
    inline bool check(int now,int len){return len<M?(ku[(1<<len)|now]!=-1):uk[len].count(now);}
	inline double &Get(int now,int len){return len<M?ku[(1<<len)|now]:uk[len][now];}
}T;
inline signed shift(int now,int len){return ((now>>(len+1))<<len)|(now&((1<<len)-1));}
inline double dfs(int now,int len){
	if (len<=k) return 0;
	if (T.check(now,len)) return T.Get(now,len);
	rr double &ans=T.Get(now,len); ans=0;
	for (rr int i=0,j=len-1;i<=j;++i,--j){
		rr double t1=dfs(shift(now,i),len-1)+((now>>i)&1);
		if (i==j) {ans+=t1; continue;}
		rr double t2=dfs(shift(now,j),len-1)+((now>>j)&1);
		ans+=2*(t1>t2?t1:t2);
	}
	return ans/=len;
}
signed main(){
    scanf("%d%d",&n,&k),k=n-k,T.Init();
	for (rr int i=0;i<n;++i){
		rr char c=getchar();
		while (c!='W'&&c!='B') c=getchar();
		now|=(c=='W')<<i;
	}
	return !printf("%lf",dfs(now,n)); 
}
posted @ 2020-08-12 21:23  lemondinosaur  阅读(78)  评论(0编辑  收藏  举报