Address
洛谷 P1654
BZOJ 4318
Solution
- 很容易想到
f[i] 表示就前
i 次操作的期望贡献
- 但发现一个问题:长度为
X 的仅由
1 组成的一段的贡献是
X3 ,故只记录
f[i] 无法转移
- 但如果以
i−1 为结尾的,最长的仅由
1 组成的段长度为
x ,那么如果第
i 次操作成功则最后一段对答案的贡献由
x3 变成
(x+1)3
- 也就是说贡献加上了
-
(x+1)3−x3=3x2+3x+1
- 所以记录
-
g1[i] 表示前
i 次操作,以
i 为结尾,仅由
1 组成的最长的段的期望长度
-
g2[i] 表示前
i 次操作,以
i 为结尾,仅由
1 组成的最长的段的长度的二次方的期望值
-
g1 的转移显然
-
g1[i]=(g1[i−1]+1)×pi
- 其中
pi 表示第
i 次操作成功的概率
-
g2 的转移,由于
(x+1)2−x2=2x+1 ,所以
-
g2[i]=(g2[i−1]+2×g1[i−1]+1)×pi
-
f 的转移也出来了
-
f[i]=f[i−1]×(1−pi)+(f[i−1]+3×g2[i−1]+3×g1[i−1]+1)×pi
- 复杂度
O(n)
Code
#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;
}