Foreign Postcards

题意:

给定 n 张排成一堆的的卡片,每一次从堆顶上等概率随机取出 [1~当前卡片数] 个卡片,如果堆顶的卡片是反面朝上,

则将所有取出的卡片翻转,求问期望取出多少个反面朝上的卡片。

 

解法:

考虑dp,首先有期望的可加性得

$ans = \sum_{i=1}^n{ P(card_i \  is \  reversed \  when \  got) }$

这样考虑求后面的概率。

用 $f(i)$ 表示以 $i$ 为取出的卡片的顶上的卡片的概率。

$f(1) = 1$

$f(i) = \sum{ \frac{f(j)}{n-j+1} }$

这样记$h(i,0), h(i,1)$ 分别表示第 $i$ 张卡片被一张正面朝上的卡消去 和 被一张反面朝上的卡消去的概率。

从而有

$$h(i,0) = \sum_{1 \leq j \leq i, S(j-1) = C}{ f(j) \frac{n-i+1}{n-j+1} }$$

$h(i,1)$ 递推式同理。

对两个式子记一下前缀和,$O(n)$

 

#include <iostream>
#include <cstdio>
#include <cstring>

#define LD double
#define N 1000010

using namespace std;

int n;
LD f[N];
char S[N];

int main()
{
    freopen("foreign.in", "r", stdin);
    freopen("foreign.out", "w", stdout);
    while(~scanf("%s",S))
    {
        n = strlen(S);
        f[1] = 1;
        f[2] = 1.0 / (LD)n;
        for(int i = 2;i < n;i++)
            f[i+1] = f[i] + f[i] / (n-i+1);
        LD sumC = 0, sumW = 0, ans = 0;
        for(int i = 1;i <= n;i++)
        {
            if(S[i-1] == 'C') sumC += f[i] / (n-i+1.0);
            else sumW += f[i] / (n-i+1.0);
            if(S[i-1] == 'C') ans += (n-i+1.0) * sumW;
            else ans += (n-i+1.0) * sumC;
        }
        printf("%.10lf\n", ans);
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}
View Code

 

posted @ 2017-05-01 13:05  lawyer'  阅读(405)  评论(0编辑  收藏  举报