dp五大步
1.状态表示
f i , j f_{i,j} fi,j 表示在 i i i 个硬币中有 j j j 个硬币朝上的概率。
2.边界
0 0 0 个硬币一定只能有 0 0 0 个朝上,所以 f 0 , 0 = 1 f_{0,0}=1 f0,0=1。
3.目标
题目要求正面朝上的比反面朝上的多,所以满足条件的有
⌈
N
2
⌉
\lceil\frac{N}{2}\rceil
⌈2N⌉ 到
N
N
N 面朝上。
所以最后输出
∑
i
=
⌈
N
2
⌉
N
f
N
,
i
\sum_{i=\lceil\frac{N}{2}\rceil}^Nf_{N,i}
∑i=⌈2N⌉NfN,i。
4.阶段划分
上一次的正反面朝上的状态。
5.转移方程
当
j
=
0
j=0
j=0,那么上次一定反面朝上。
当
0
<
j
≤
i
0<j\le i
0<j≤i,就有正面和反面两种情况。
f
i
,
j
=
{
f
i
−
1
,
j
×
(
1
−
p
i
)
j
=
0
f
i
−
1
,
j
×
(
1
−
p
i
)
+
f
i
−
1
,
j
−
1
×
p
i
0
<
j
≤
i
f_{i,j}=\left\{ \begin{aligned} f_{i-1,j}\times(1-p_i) &&& j=0\\ f_{i-1,j}\times(1-p_i)+f_{i-1,j-1}\times p_i&&& 0<j\le i \end{aligned} \right.
fi,j={fi−1,j×(1−pi)fi−1,j×(1−pi)+fi−1,j−1×pij=00<j≤i
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n;
double f[3010][3010], ans;
signed main(){
cin >> n;
f[0][0] = 1;
for (int i = 1; i <= n; i++){
double x;
cin >> x;
f[i][0] = f[i - 1][0] * (1 - x);
for (int j = 1; j <= i; j++) f[i][j] = f[i - 1][j - 1] * x + f[i - 1][j] * (1 - x);
}
for (int i = (n + 1) / 2; i <= n; i++) ans += f[n][i];
printf("%.10lf", ans);
return 0;
}