[洛谷] OSU!(期望DP)
Problem
Solution
- 期望的线性性质
设 \(f[i]\) 表示以 \(i\) 结尾的连续 \(1\) 区间的期望贡献(\(x^1\)),\(g[i]\) 表示以 \(i\) 结尾的连续 \(1\) 区间的期望贡献(\(x^2\)),则有:
\[f[i]=p_i(f[i-1]+1)
\]
\[g[i]=p_i(g[i-1]+2f[i-1]+1)
\]
(因为 \((x+1)^2=x^2+2x+1\))
类似的,可以设 \(h[i]\) 表示以 \(i\) 结尾的连续 \(1\) 区间的期望贡献(\(x^3\)),则有 \(h[i]=p_i(h[i-1]+3g[i-1]+3f[i-1]+1)\)(因为 \((x+1)^3=x^3+3x^2+3x+1\))。由于不方便统计答案(直接加上去会有一些 \("1"\) 重复计算贡献),我们又可以根据期望的线性性质:
\[E((x+1)^3) = E(x^3)+E(3x^2+3x+1)
\]
计算每个位置上 \(1\) 的对答案增加的期望贡献。位置 \(i\) 上选 \("1"\) 对答案增加的期望贡献是:\(p_i(3g[i-1]+3f[i-1]+1)\),所以最后的答案是:
\[\sum p_i(3g[i-1]+3f[i-1]+1)
\]
时间复杂度 \(O(n)\)。
Code
Talk is cheap.Show me the code.
#include<bits/stdc++.h>
using namespace std;
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
return x * f;
}
const int N = 100007;
int n;
double p[N],f[N],g[N],h[N];
int main()
{
n = read();
for(int i=1;i<=n;++i) scanf("%lf",&p[i]);
double ans = 0;
for(int i=1;i<=n;++i) {
f[i] = p[i] * (f[i-1] + 1);
g[i] = p[i] * (g[i-1] + 2*f[i-1] + 1);
ans += p[i] * (3*g[i-1] + 3*f[i-1] + 1);
}
printf("%.1lf",ans);
return 0;
}
/*
3
0.5
0.5
0.5
6.0
*/
Summary
主要是期望的线性性质。注意想当然地加会重复计算贡献(自己手推一下会发现),要计算每个位置增加的期望贡献。