很容易想到定义 d p [ i ] dp[i] dp[i]是已经执行了前 i i i个事件,还期望讲多久结束
d p [ i ] = p [ i ] ∗ ( d p [ i + 1 ] + 1 ) + ( 1 − p [ i ] ) ∗ ( d p [ i − 1 ] + 1 ) dp[i]=p[i]*(dp[i+1]+1)+(1-p[i])*(dp[i-1]+1) dp[i]=p[i]∗(dp[i+1]+1)+(1−p[i])∗(dp[i−1]+1)
发现这个式子前后都有依赖,可以高斯消元,但这题似乎卡这个精度
我 们 这 么 定 义 d p [ i ] \color{Red}我们这么定义dp[i] 我们这么定义dp[i]为执行前 i i i个事件期望多久
d p [ i ] = d p [ i − 1 ] + 1 + ( 1 − p [ i − 1 ] ) ∗ ( d p [ i ] − d p [ i − 2 ] ) dp[i] = dp[i-1]+1+(1-p[i-1])*(dp[i]-dp[i-2]) dp[i]=dp[i−1]+1+(1−p[i−1])∗(dp[i]−dp[i−2])
是不是很迷~
d p [ i − 1 ] + 1 dp[i-1]+1 dp[i−1]+1很好理解,就是继承前面的状态,且拿出一次机会来执行第 i i i件事
有 p [ i − 1 ] 概 率 成 功 , 从 i − 1 转 移 到 i , 此 时 不 需 要 额 外 的 花 费 有p[i-1]概率成功,从i-1转移到i,此时不需要额外的花费 有p[i−1]概率成功,从i−1转移到i,此时不需要额外的花费
有 1 − p [ i − 1 ] 概 率 失 败 , 从 i − 1 掉 到 了 i − 2 有1-p[i-1]概率失败,从i-1掉到了i-2 有1−p[i−1]概率失败,从i−1掉到了i−2
那 么 现 在 需 要 从 i − 2 转 移 到 i 那么现在需要从i-2转移到i 那么现在需要从i−2转移到i
也 就 是 需 要 从 i − 2 转 移 到 i − 1 , 花 费 d p [ i − 1 ] − d p [ i − 2 ] 也就是需要从i-2转移到i-1,花费dp[i-1]-dp[i-2] 也就是需要从i−2转移到i−1,花费dp[i−1]−dp[i−2]
从 i − 1 转 移 到 i , 花 费 d p [ i ] − d p [ i − 1 ] 从i-1转移到i,花费dp[i]-dp[i-1] 从i−1转移到i,花费dp[i]−dp[i−1]
相 加 花 费 得 到 上 面 的 式 子 相加花费得到上面的式子 相加花费得到上面的式子
对 d p [ i ] dp[i] dp[i]移项可以得到
d p [ i ] = d p [ i − 1 ] + 1 − ( 1 − p [ i − 1 ] ) ∗ d p [ i − 2 ] p [ i − 1 ] dp[i]=\frac{dp[i-1]+1-(1-p[i-1])*dp[i-2]}{p[i-1]} dp[i]=p[i−1]dp[i−1]+1−(1−p[i−1])∗dp[i−2]
最后 d p [ n + 1 ] dp[n+1] dp[n+1]即位答案
#include <bits/stdc++.h> using namespace std; const int maxn=2e5+10; int n; double dp[maxn],p[maxn]; int main() { cin >> n; for(int i=1;i<=n;i++) cin >> p[i]; dp[0]=dp[1]=0; for( int i=2;i<=n+1;i++ ) dp[i] = ( dp[i-1]+1.0-( 1.0-p[i-1] )*dp[i-2] )/p[i-1]; printf("%.3lf",dp[n+1]); }