NOIP 模拟 $19\; \rm v$
阅读原文时间:2023年07月11日阅读:1

一道概率与期望的状压题目

这种最优性的题目,我们一般都是倒着转移,因为它的选择是随机的所以我们无法判断从左还是从右更有,所以我们都搜一遍

时间一定会爆,采用记忆化搜索,一种状态的答案一定是固定的,所以可以记忆化

但是空间也会爆,当状态大于 \(2^{25}\) 次方时,我们选择使用一个 \(map\) ,小于时就用一个数组

对于数组,我们先打上标记,然后直接记忆化

注意,总的状态一定要在最高位再高一位设成 \(1\),因为 \(00000\) 和 \(000\) 不是一种状态,但是若不加,就会判成一种状态

Code

#include<bits/stdc++.h>
#define ri register signed
#define p(i) ++i
using namespace std;
namespace IO{
    char buf[1<<21],*p1=buf,*p2=buf;
    #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++
    template<typename T>inline void read(T &x) {
        ri f=1;x=0;register char ch=getchar();
        while(ch<'0'||ch>'9') {if (ch=='-') f=0;ch=getchar();}
        while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        x=f?x:-x;
    }
}
using IO::read;
namespace nanfeng{
    #define FI FILE *IN
    #define FO FILE *OUT
    template<typename T>inline T cmax(T x,T y) {return x>y?x:y;}
    template<typename T>inline T cmin(T x,T y) {return x>y?y:x;}
    typedef double db;
    map<int,db> dph;
    db dps[1<<25];
    int n,k,st,wnm;
    char s[33];
    int calc(int st,int cur) {
        ri tmp=st>>cur,bc=st&((1<<cur-1)-1);
        return tmp<<(cur-1)|bc;
    }
    db dfs(int st,int siz) {
        if (siz==n-k) return 0.0;
        if (siz>24&&dph.find(st)!=dph.end()) return dph[st];
        if (siz<=24&&dps[st]!=-1.0) return dps[st];
        register db res=0.0;
        ri lm=siz>>1;
        for (ri i(1);i<=lm;p(i)) {
            ri tmp1=st>>i-1&1,tmp2=st>>siz-i&1;
            ri st1=calc(st,i),st2=calc(st,siz-i+1);
            res+=2.0*cmax(dfs(st1,siz-1)+(db)tmp1,dfs(st2,siz-1)+(db)tmp2)/siz;
        }
        if (siz&1) {
            lm+=1;
            ri tmp1=st>>lm-1&1,st1=calc(st,lm);
            res+=(dfs(st1,siz-1)+(db)tmp1)/siz;
        }
        return siz>24?dph[st]=res:dps[st]=res;
    }
    inline int main() {
        FI=freopen("nanfeng.in","r",stdin);
        // FO=freopen("nanfeng.out","w",stdout);
        for (ri i(0);i<1<<25;p(i)) dps[i]=-1.0;
        read(n),read(k);
        scanf("%s",s+1);
        for (ri i(1);i<=n;p(i)) st|=(s[i]=='W')<<n-i,wnm+=(s[i]=='W');
        st|=1<<n;
        printf("%.10lf\n",dfs(st,n));
        return 0;
    }
}
int main() {return nanfeng::main();}