【2018-国庆雅礼-NOIP-培训】-D3T2- v

题解:

显然可以得到一个 $O(2^n∗n)$ 的状压 dp 做法,记录每个球是否还未被移除,然后按照最优策 略期望移除白球数。

事实上,有很多重复状态,也就是剩下的球的颜色序列相同时,结果是一样的。

考虑将状态记成剩下的颜色序列,长度较小时,直接用数组存,较大时用 map。

状态数不难得到一个上界 $\sum_{i=1}^n min{2^i,C_n^i}$ 。(事实上,最大值为$\sum_{i=1}^{n+1} Fib(i)$ ,但是这不 noip)

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include<bits/stdc++.h>
using namespace std;

const int maxn=30+5;
int n,k;
char s[maxn];

namespace ${
const int xxx=24;
double a[1<<xxx+1];
map<int,double> m[maxn];
inline void init(){
for(int i=0;i<1<<xxx+1;++i)
a[i]=-1;
}
inline bool count(int bit,int len){
if(len<=xxx)
return a[1<<len|bit]!=-1;
else
return m[len].count(bit);
}
inline double&find(int bit,int len){
if(len<=xxx)
return a[1<<len|bit];
else
return m[len][bit];
}
}
inline int erase(int bit,int k){
return bit&(1<<k)-1|bit>>1&-1<<k;
}
inline double max_(double a,double b){
return a>=b?a:b;
}
double dfs(int bit,int len){
if(len<=k)
return 0;
if($::count(bit,len))
return $::find(bit,len);
double&res=$::find(bit,len);
res=0;
for(int i=0,j=len-1;i<=j;++i,--j)
if(i<j)
res+=max_(dfs(erase(bit,i),len-1)+(bit>>i&1),dfs(erase(bit,j),len-1)+(bit>>j&1))*2;
else
res+=dfs(erase(bit,i),len-1)+(bit>>i&1);
return res/=len;
}

int main()
{
$::init();
scanf("%d%d%s",&n,&k,s);
k=n-k;
int bit=0;
for(int i=0;i<n;++i)
bit|=(s[i]=='W')<<i;
printf("%.10f\n",dfs(bit,n));
return 0;
}