Coins 概率+DP基础

题面翻译

N 枚硬币,第 i 枚硬币有 pi​ 的概率正面朝上,有 1−pi​ 的概率反面朝上。 扔完所有硬币,求正面朝上的银币数比反面朝上的银币数多的概率。

题目描述

N を正の奇数とします。

N 枚のコインがあります。 コインには 1, 2, …, 1, 2, …, N と番号が振られています。 各 i (1 ≤ i ≤ N) について、コイン i を投げると、確率 pi​ で表が出て、確率 1 − pi​ で裏が出ます。

太郎君は N 枚のコインをすべて投げました。 このとき、表の個数が裏の個数を上回る確率を求めてください。

输入格式

入力は以下の形式で標準入力から与えられる。

N 1p1​ 2p2​ …… pN​

输出格式

表の個数が裏の個数を上回る確率を出力せよ。 絶対誤差が 10−910−9 以下ならば正解となる。

样例 #1

样例输入 #1

3
0.30 0.60 0.80

样例输出 #1

0.612

样例 #2

样例输入 #2

1
0.50

样例输出 #2

0.5

样例 #3

样例输入 #3

5
0.42 0.01 0.42 0.99 0.42

样例输出 #3

0.3821815872

提示

制約

  • N は奇数である。
  • 1 ≤ N ≤ 2999
  • pi​ は実数であり、小数第 22 位まで与えられる。
  • 0 < pi​ < 1

Sample Explanation 1

表の個数が裏の個数を上回るような各ケースの確率を計算すると、次のようになります。 - (コイン 1, コイン 2, コイン 3) = (表, 表, 表)(コイン 1, コイン 2, コイン 3) = (表, 表, 表) となる確率は、0.3 × 0.6 × 0.8 = 0.1440.3 × 0.6 × 0.8 = 0.144 である。 - (コイン 1, コイン 2, コイン 3) = (裏, 表, 表)(コイン 1, コイン 2, コイン 3) = (裏, 表, 表) となる確率は、0.7 × 0.6 × 0.8 = 0.3360.7 × 0.6 × 0.8 = 0.336 である。 - (コイン 1, コイン 2, コイン 3) = (表, 裏, 表)(コイン 1, コイン 2, コイン 3) = (表, 裏, 表) となる確率は、0.3 × 0.4 × 0.8 = 0.0960.3 × 0.4 × 0.8 = 0.096 である。 - (コイン 1, コイン 2, コイン 3) = (表, 表, 裏)(コイン 1, コイン 2, コイン 3) = (表, 表, 裏) となる確率は、0.3 × 0.6 × 0.2 = 0.0360.3 × 0.6 × 0.2 = 0.036 である。 よって、表の個数が裏の個数を上回る確率は、0.144 + 0.336 + 0.096 + 0.036 = 0.6120.144 + 0.336 + 0.096 + 0.036 = 0.612 です。

Sample Explanation 2

例えば、0.5000.5000000010.499999999 などを出力しても正解となります。

题目分析:

给一堆硬币,求正面比反面多的概率

dp[i][j]表示的是i个硬币时正面硬币是j个的概率

p[i]表示概率

初始化:

dp[1][0]就是第一个是反面,也就是1.0-p[1];

dp[1][1]就是第一个正面,也就是p[1];

当前dp[i][j]的状态由前一个硬币dp[i-1][]得来,前一个硬币有两种状态,正面和反面,对应的概率就是p[i]和 1.0-p[i];

状态转移方程:dp[i][j] = dp[i - 1][j - 1] * p[i] + dp[i - 1][j] * (1.0 - p[i]); 

特殊处理:

 每个硬币都可能出现全部是反面的情况,状态转移方程中出现了j-1,显然不适合,特判一下即可;

 AC代码:

#include 
using namespace std;
const int N = 3e3+5;
double p[N];
double dp[N][N];
int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; ++i)cin >> p[i];
	dp[1][1] = p[1]; 
	dp[1][0] = 1.0 - p[1];
	for (int i = 2; i <= n; ++i)
		for (int j = 0; j <= i; ++j) {
			if (j == 0)
			{ 
				dp[i][j] = dp[i - 1][j] * (1.0 - p[i]);
				continue;
			}
			dp[i][j] = dp[i - 1][j - 1] * p[i] + dp[i - 1][j] * (1.0 - p[i]);
		}
	double res = 0;
	for (int i = (n + 1) / 2; i <= n; i++) //至少(n+1)/2个正面
		res += dp[n][i];
	printf("%.10f\n", res);
}

你可能感兴趣的:(题解,c++,DP,动态规划,概率)