Luogu P1654 概率DP


原题链接

题意
  • 我们面前有一个长度为 N N N的01序列,位置 a i a_i ai p i p_i pi 的概率是1,否则为0。

  • 序列中,一段长为 x x x 的连续1会带来 x 3 x^3 x3 的加分(这段全为1的子区间不能被更长的全1区间包含)

  • 求得分期望

思路
  • 考虑DP的方法, F i F_i Fi 表示前i位的期望加分。然后对于第 i + 1 i + 1 i+1

    • 如果为0,则对于总体加分有0贡献

    • 我们定义以i为结尾,全1区间长度的期望是

      E ( L i ) E(L_i) E(Li)

    • 然后,如果第i + 1位为1,则贡献为

      E ( ( L i + 1 ) 3 ) − E ( L i 3 ) = 3 ∗ E ( L i 2 ) + 3 ∗ E ( L i ) + 1 E((L_i + 1)^3) - E(L_i^3) = 3 * E(L_i^2) + 3 * E(L_i) + 1 E((Li+1)3)E(Li3)=3E(Li2)+3E(Li)+1

    • 这是因为i + 1位为1时,所有以i为结尾的全1区间都会延长至i + 1,从而我们必须要放弃之前的这部分贡献,然后加上新的部分,最终得到的是一个二次多项式

    • 然后考虑如何计算 E ( L i 2 ) E(L_i^2) E(Li2) E ( L i ) E(L_i) E(Li)

      • 对于 E ( L i ) E(L_i) E(Li), 当i + 1位为0时,显然 E ( L i + 1 ) E(L_{i + 1}) E(Li+1) 为0(毕竟不可能成为全一区间结尾了),i + 1位为1时,显然有
        E ( L i + 1 ) = E ( L i ) + 1 E(L_{i + 1}) = E(L_i) + 1 E(Li+1)=E(Li)+1

      • 对于 E ( L i 2 ) E(L_i^2) E(Li2), 当i + 1位为0时,显然 E ( L i + 1 ) E(L_{i + 1}) E(Li+1) 为0(原因同上),i + 1位为1时,有
        E ( L i + 1 2 ) = E ( ( L i + 1 ) 2 ) = E ( L i 2 ) + 2 ∗ E ( L i ) + 1 E(L_{i + 1}^2) = E((L_i + 1)^2) = E(L_i^2) + 2 * E(L_i) + 1 E(Li+12)=E((Li+1)2)=E(Li2)+2E(Li)+1

      • 总起来也就是说
        E ( L i + 1 ) = p i + 1 ∗ ( E ( L i ) + 1 ) E ( L i + 1 2 ) = p i + 1 ∗ E ( ( L i + 1 ) 2 ) = p i + 1 ∗ ( E ( L i 2 ) + 2 ∗ E ( L i ) + 1 ) E(L_{i + 1}) = p_{i + 1} * (E(L_i) + 1) \\ E(L_{i + 1}^2) = p_{i + 1} * E((L_i + 1)^2) = p_{i + 1} * (E(L_i^2) + 2 * E(L_i) + 1) E(Li+1)=pi+1(E(Li)+1)E(Li+12)=pi+1E((Li+1)2)=pi+1(E(Li2)+2E(Li)+1)


  • 由i + 1位为1时对加分贡献的式子,可得
    F i + 1 = F i + p i + 1 ∗ ( 3 ∗ E ( L i 2 ) + 3 ∗ E ( L i ) + 1 ) F_{i + 1} = F_i + p_{i + 1} * (3 * E(L_i^2) + 3 * E(L_i) + 1) Fi+1=Fi+pi+1(3E(Li2)+3E(Li)+1)

一边计算 F i F_i Fi 一边计算 E ( L i ) E(L_i) E(Li) E ( L i 2 ) E(L_i^2) E(Li2) 即可

AC代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int n;
double p;

int main()
{
	scanf("%d", &n);
	double acc = 0;
	double x2 = 0, x = 0;
	for (int i = 0; i < n; ++i)
	{
		scanf("%lf", &p);
		acc += p * (3 * x2 + 3 * x + 1);
		x2 = p * (x2 + 2 * x + 1);
		x = p * (x + 1);
	}
	printf("%.1f", acc);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值