VOJ - OSU! (概率DP)

OSU!

题目链接: OSU! HYSBZ - 4318

题意

osu 是一款群众喜闻乐见的休闲软件。

我们可以把osu的规则简化与改编成以下的样子:

一共有n次操作,每次操作只有成功与失败之分,成功对应1,失败对应0,n次操作对应为1个长度为n的01串。在这个串中连续的 X个1可以贡献X^3^ 的分数,这x个1不能被其他连续的1所包含(也就是极长的一串1,具体见样例解释)

现在给出n,以及每个操作的成功率,请你输出期望分数,输出四舍五入后保留1位小数。


思路

这里就参考大佬的博客了

  大牛都说是水题水题,然而被折磨的欲仙欲死,不过终于在 s_z_l老爷 和 Ngshily大爷 的帮助下搞清楚了,写一写帮助后人吧。。。

1>

    首先我们要求的是E(x^3^),我们需要明确这里的x^3^ 指的是得分。

    我们按照原本的思路,考虑每一位的∆,那么我们假设这一位是1,那么 E((x + 1)^3^ ) = E(x^3^ ) + ∆;

      ∆ = E((x + 1)^3^) - E(x^3^ ) = E((x + 1)^3^ - x^3^) = E(x^2^ + 2x + 1 + x^2^ + x + x^2) = E(3x^2^ + 3x + 1) = 3E(x^2^) + 3E(x) + 1.

    所以我们得到了∆的表达式,那么这一位是1的概率是pi,所以需要给∆乘上pi –> E((x + 1)^3^ ) = E((x)^3^ ) + p[x + 1] * (3E((x)^2^) + 3E(x) + 1).

2>

    然后我们需要计算E(x^2^), E(x) 的价值,我们依然要明确这里的x是结尾连续1的长度的期望,和上面的x并不是一个意思,我们用l代替。

    同样的我们假设这一位是1,那么E((l + 1)^2^) = E(l^2^) + ∆ –> ∆ = 2E(l) + 1

    所以我们应该整个乘上p[l + 1],所以E((l + 1)^2^) = p[l + 1] * (E(l^2^) + ∆).

遇到的几个问题:

    1> 首先我们需要明确 E(x^3^ ) 这个是答案值,我们这样考虑,E(x^3^ ) = E((x - 1)^3^ ) + ∆。E((x - 1)^3^)是不变的,我们需要给他加上新的值乘上概率,也就是说我们应该写成 E(x^3^ ) = E((x - 1)^3^) + p[x] * ∆. 注意在∆前面乘上p[x],这代表着这一位的可能取值。

    2> 在递推过程中,∆ = 3E((x - 1)^2^) + 3E(x - 1) + 1。也就是说这一位需要的是上一位的E(x^2^)和E(x)。这里的x是指长度,所以我们在解决E(x^2^)的问题时,同样可以一样考虑,E(x^2^) = E((x - 1)^2^) + ∆,但是注意这是这一位取1的值的可能取值,那么我们应该E(x^2^) = p[x] * (E((x - 1)^2^) + ∆).

    3> 注意,1>和2>中p[x]的乘的地方是不一样的,应为一个是累加贡献,而另一个是加上以后才是这一位如果取一的取值。

    4> 在解决E(x^3^)的时候,如果用E(x^3^) - E((x - 1)^3^) = 3E(x^2^) - 3E(x) + 1。但是这是不一样的,应为我们在用E((x - 1)^3^ ) 去推理 E(x^3^ ) 所以后面应该是用3E((x - 1)^2^) + 3E(x - 1) + 1.


代码

#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++)
#define per(i,j,k) for(int i = (int)j;i >= (int)k;i --)
#define debug(x) cerr<<#x<<" = "<<(x)<<endl
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back

typedef double db;
typedef long long ll;
const int MAXN = (int)1e6+7;
const int INF = (int)0x3f3f3f3f;

int main() {
    int n;
    scanf("%d", &n);
    double ans(0), l(0), l2(0), p;
    rep(i, 1, n) {
        scanf("%lf", &p);
        ans += p * (3 * l2 + 3 * l + 1);
        l2 = p * (l2 + 2 * l + 1);
        l  = p * (l + 1);
    }
    printf("%.1lf\n", ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值