BZOJ2554 color 【概率DP】【期望DP】

题目分析:

好题。

一开始看错题了,以为是随机选两个球,编号在前的染编号在后的。

但这样仍然能获得一些启发,不难想到可以确定一个颜色,剩下的颜色是什么就无关了。

那么答案就是每种颜色的概率乘以期望。概率很好求。

考虑期望,这里存在一个"黑洞",也就是f[0]状态无论如何也不可能填满颜色,所以我们要舍弃这个状态,这样往左和往右的转移就不是对半了。

通过求出的概率作比可以发现实际上是i-1:i+1。所以可以列出DP方程

 

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn = 10200;
 5 char str[maxn];
 6 double h[maxn],f[maxn],g[maxn]; // f->expectation g->possibility
 7 
 8 int cnt[maxn];
 9 double k[maxn],b[maxn];
10 
11 void work(){
12     int ls = strlen(str);
13     for(int i=0;i<=ls;i++) g[i] = (double)i/(double)ls;
14     for(int i=1;i<ls;i++){
15     h[i] = (double)ls*(ls-1)/(double)(2*i*(ls-i));
16     }
17     k[1] = 1; b[1] = h[1];
18     for(int i=2;i<ls;i++){
19     b[i] = h[i]; k[i] = (double)(i+1)/(2*i);
20     double hh = k[i-1]*((double)(i-1)/(2*i));
21     b[i] += b[i-1]*((double)(i-1)/(2*i));
22     k[i] /= (1-hh); b[i] /= (1-hh);
23     }
24     for(int i=ls-1;i>=1;i--){
25     f[i] = f[i+1]*k[i]+b[i];
26     }
27     for(int i=0;i<ls;i++) cnt[str[i]-'A']++;
28     double ans = 0;
29     for(int i=0;i<26;i++) ans += f[cnt[i]]*g[cnt[i]];
30     printf("%.1lf\n",ans);
31 }
32 
33 int main(){
34     scanf("%s",str);
35     work();
36     return 0;
37 }

 

posted @ 2019-01-14 17:00  menhera  阅读(286)  评论(0编辑  收藏  举报