BZOJ 4318: OSU! (概率dp)

Description

osu 是一款群众喜闻乐见的休闲软件。
我们可以把osu的规则简化与改编成以下的样子:
一共有n次操作,每次操作只有成功与失败之分,成功对应1,失败对应0,n次操作对应为1个长度为n的01串。在这个串中连续的 X个1可以贡献X^3 的分数,这x个1不能被其他连续的1所包含(也就是极长的一串1,具体见样例解释)
现在给出n,以及每个操作的成功率,请你输出期望分数,输出四舍五入后保留1位小数。


Input

第一行有一个正整数n,表示操作个数。接下去n行每行有一个[0,1]之间的实数,表示每个操作的成功率。


Output

只有一个实数,表示答案。答案四舍五入后保留1位小数。


Sample Input

3
0.5
0.5
0.5


Sample Output

6.0


HINT

样例说明:
000分数为0,001分数为1,010分数为1,100分数为1,101分数为2,110分数为8,011分数为8,111分数为27,总和为48,期望为48/8=6.0
N<=100000


Solution

这题求得分的期望,我们很容易想到动态规划
但这是期望怎样计算呢?概率dp
假设确定了01序列。我们假设当前位置是0的话,则贡献为0,这个不用计算。否则贡献为
(x+1)3x3=3x2+3x+1 (其中x为一个位置最长的全是1的后缀的长度)
注意是贡献,设这个贡献为k,我们要求期望得分(即得分的均值),则f[i] = f[i-1] + k * a[i]; //a[i]是能产生此贡献的概率,是读入的

f[n]就是最终答案。

我们OIER算期望当然不能根据定义傻傻求均值,我们一般用递推方法,通过算概率来求。

根据上面的公式,我们要知道贡献k,必须知道 x x2,这两个数一个数是长度的期望,另一数长度的平方的期望(注意‘期望’的位置)。我们知道期望的和等于和的期望,这是数学期望的线性性质。但期望的平方不等于平方的期望,所以我们要递推求 x2

我们维护三个数组, x 的期望l1[], x2的期望l2[], 得分的期望f[]。然后线性递推过来就行了。

Summary

对于概率dp、求期望这种数学和dp合二为一的东西我比较少见,但见到就是送分了(因为数学的缺陷连期望都不会求。。),所以一定要多刷此方面的题,总结规律、积累经验。


Code

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstring>
#define N 100010

using namespace std;

int n;
double a[N], l1[N], l2[N], f[N];

int main(){

    scanf("%d", &n);

    for(int i = 1; i <= n; i++)  scanf("%lf", &a[i]);
    l1[0] = l2[0] = 0.00;
    for(int i = 1; i <= n; i++){
      l1[i] = (l1[i-1] + 1) * a[i];
      l2[i] = (l2[i-1] + 2 * l1[i-1] + 1) * a[i];
      f[i] = f[i-1] + (3 * l2[i-1] + 3 * l1[i-1] + 1) * a[i]; 
    }

    printf("%.1lf\n", f[n]);

    return 0;
} 

该怎么描述我们的相遇,就像某种极低概率的奇迹。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值