正题
题目大意
nnn个球排成一排颜色不同,每次选择一个随机的[1..n][1..n][1..n]中的xxx,然后删掉第xxx个或第n−x+1n-x+1n−x+1个数,求删kkk次之后删掉的白球最多,求删掉数量的期望值
解题思路
考虑状态压缩dpdpdp,定义第一个111所在位数表示剩下的球数,111表示该位置是白球,000表示该位置是黑球。设fsf_sfs表示状态为sss时的最小期望值。
del(s,i)del(s,i)del(s,i)表示sss去掉第iii个球后的状态,有状态转移方程fs=∑i=1lmax{fdel(s,i)+one(s,i),fdel(s,n−i+1)+one(s,n−i+1)}lf_s=\frac{\sum_{i=1}^lmax\{f_{del(s,i)}+one(s,i),f_{del(s,n-i+1)}+one(s,n-i+1)\}}{l}fs=l∑i=1lmax{fdel(s,i)+one(s,i),fdel(s,n−i+1)+one(s,n−i+1)}
这样的时间复杂度为O(2nn)O(2^nn)O(2nn)
但是有许多状态是没有使用的,我们对于小的sss可以用一个桶存,对于大的sss我们可以用mapmapmap来存即可
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define XJQ using
#define AK namespace
#define IOI std
XJQ AK IOI;
const int N=35,Lim=1<<24;
int n,k;
double a[Lim];
map<int,double> m;
char str[N];
bool live(int x,int l){int z=x|(1<<l);if(z<Lim)return (a[z]!=-1);return m.count(z);
}
double get(int x,int l){int z=x|(1<<l);if(z<Lim)return a[z];return m[z];
}
void change(int x,int l,double val){int z=x|(1<<l);if(z<Lim) a[z]=val;else m[z]=val;return;
}
int del(int x,int w)
{return ((x>>w+1)<<w)+x%(1<<w);}
double dfs(int s,int l){if(l<=n-k)return 0;if(live(s,l))return get(s,l);double ans=0;for(int i=0;i<l;i++) ans+=(max(dfs(del(s,i),l-1)+((s>>i)&1),dfs(del(s,l-i-1),l-1)+((s>>(l-i-1))&1)))/l;change(s,l,ans);return ans;
}
int main()
{scanf("%d%d",&n,&k);scanf("%s",str);int s=0;for(int i=0;i<Lim;i++)a[i]=-1;for(int i=0;i<n;i++)s|=((str[i]=='W')<<i);printf("%.6lf",dfs(s,n));
}