[BZOJ4318]OSU! (期望 DP)

Address

洛谷 P1654
BZOJ 4318

Solution

  • 很容易想到 f [ i ] f[i] 表示就前 i i 次操作的期望贡献
  • 但发现一个问题:长度为 X X 的仅由 1 1 组成的一段的贡献是 X 3 X^3 ,故只记录 f [ i ] f[i] 无法转移
  • 但如果以 i 1 i-1 为结尾的,最长的仅由 1 1 组成的段长度为 x x ,那么如果第 i i 次操作成功则最后一段对答案的贡献由 x 3 x^3 变成 ( x + 1 ) 3 (x+1)^3
  • 也就是说贡献加上了
  • ( x + 1 ) 3 x 3 = 3 x 2 + 3 x + 1 (x+1)^3-x^3=3x^2+3x+1
  • 所以记录
  • g 1 [ i ] g_1[i] 表示前 i i 次操作,以 i i 为结尾,仅由 1 1 组成的最长的段的期望长度
  • g 2 [ i ] g_2[i] 表示前 i i 次操作,以 i i 为结尾,仅由 1 1 组成的最长的段的长度的二次方的期望值
  • g 1 g_1 的转移显然
  • g 1 [ i ] = ( g 1 [ i 1 ] + 1 ) × p i g_1[i]=(g_1[i-1]+1)\times p_i
  • 其中 p i p_i 表示第 i i 次操作成功的概率
  • g 2 g_2 的转移,由于 ( x + 1 ) 2 x 2 = 2 x + 1 (x+1)^2-x^2=2x+1 ,所以
  • g 2 [ i ] = ( g 2 [ i 1 ] + 2 × g 1 [ i 1 ] + 1 ) × p i g_2[i]=(g_2[i-1]+2\times g_1[i-1]+1)\times p_i
  • f f 的转移也出来了
  • f [ i ] = f [ i 1 ] × ( 1 p i ) + ( f [ i 1 ] + 3 × g 2 [ i 1 ] + 3 × g 1 [ i 1 ] + 1 ) × p i f[i]=f[i-1]\times(1-p_i)+(f[i-1]+3\times g_2[i-1]+3\times g_1[i-1]+1)\times p_i
  • 复杂度 O ( n ) O(n)

Code

  • 主体部分仅 10 行,可用于刷短代码
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)

const int N = 1e5 + 5;

int n;
double p[N], f[N], g1[N], g2[N];

int main()
{
	int i;
	std::cin >> n;
	For (i, 1, n) scanf("%lf", &p[i]);
	For (i, 1, n)
	{
		g1[i] = p[i] * (g1[i - 1] + 1);
		g2[i] = p[i] * (g2[i - 1] + g1[i - 1] * 2 + 1);
		f[i] = f[i - 1] * (1.0 - p[i]) +
			(f[i - 1] + g2[i - 1] * 3 + g1[i - 1] * 3 + 1) * p[i];
	}
	printf("%.1lf\n", f[n]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/84329143