P1654 OSU! 期望概率DP
P1654 OSU!
题目链接
期望概率DP。
设\(x\)为连续1的个数,那么多一个1他增加的贡献就是:\((x + 1) ^ 3 - x ^ 3 = 3 * x ^ 2 + 3 * x + 1\)
所以我们需要维护\(x\)的期望和\(x ^ 2\)的期望。
\(x\)的期望:\(x[i] = (x[i - 1] + 1) * p[i]\);
\(x ^ 2\)的期望:\(x2[i] = (x2[i - 1] + 2 * x[i - 1] + 1) * p[i]\);
答案的期望:\(x3[i] = x3[i - 1] + (3 * x2[i - 1] + 3 * x[i - 1] + 1) * p[i]\)。
有一个地方困扰了我好久,就是为什么算x, x2的时候要把x[i - 1], x2[i - 1]括到括号里,而x3就不用。
首先要清楚x,x2数组的定义是结尾为i的连续的1的长度,结尾为i的连续的1的长度的平方。而x3数组的定义是最终答案的期望,并不是结尾为i的连续的1的长度的三次方。
所以对于x3:\(ans = \displaystyle \sum_{i=1}^{n} E[i]\),对于x,x2就是i-1的期望加上新的贡献再乘上概率。
或者也可以这么写:\(x3[i] = (x3[i - 1] + 3 * x2[i - 1] + 3 * x[i - 1] + 1) * p[i] + x3[i - 1] * (1 - p[i])\)。
#include <bits/stdc++.h>
using namespace std;
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
const int N = 1e5 + 5;
int n;
double a[N], x[N], x_2[N], x_3[N];
int main() {
n = read();
for(int i = 1;i <= n; i++) scanf("%lf", &a[i]);
for(int i = 1;i <= n; i++) {
x[i] = (x[i - 1] + 1) * a[i];
x_2[i] = (x_2[i - 1] + 2 * x[i - 1] + 1) * a[i];
x_3[i] = x_3[i - 1] + (3 * x_2[i - 1] + 3 * x[i - 1] + 1) * a[i];
}
printf("%.15lf", x_3[n]);
return 0;
}