一.古典概率
定义:设一个实验有n个等可能的结果,而事件E恰包含其中的M个结果,则事件E的概率,记为
P
(
E
)
P(E)
P(E),定义为
P
(
E
)
=
M
/
N
P(E)=M/N
P(E)=M/N
说得这么高深,其实就是小学就学过的那种概率,这里就够用了。
二.典例讲解
1.题目
传送门
题意:给出n种硬币,每种有个数和存活的概率,一直刷,直到没有硬币或者只有一种硬币存活下来,输出每种硬币最后存活的概率。
2.题解
这道题目乍一看其实并不难,只需几个公式就可以推出来。
首先,我们定义一个DP数组:dp[i][j]表示第i种硬币,前j轮被淘汰的概率。
容易想到,第i种硬币第j轮被淘汰的概率是:
p
i
j
−
1
(
1
−
p
i
)
p_{i}^{j-1}(1-p_{i})
pij−1(1−pi)
(p[i]是这种硬币正面朝上的概率)
所以i在前j轮被淘汰的概率就是
d
p
[
i
]
[
j
]
=
[
p
i
0
(
1
−
p
i
)
+
p
i
1
(
1
−
p
i
)
+
.
.
.
+
p
i
j
−
1
(
1
−
p
i
)
]
n
u
m
i
=
[
(
p
i
0
+
p
i
1
+
.
.
.
+
p
i
j
−
1
)
(
1
−
p
i
)
]
n
u
m
i
=
(
1
−
p
i
j
)
n
u
m
i
\begin{aligned} dp[i][j]=&[p_{i}^{0}(1-p_{i})+p_{i}^{1}(1-p_{i})+...+p_{i}^{j-1}(1-p_{i})]^{num_{i}}\\ =&[(p_{i}^{0}+p_{i}^{1}+...+p_{i}^{j-1})(1-p_{i})]^{num_{i}}\\ =&(1-p_{i}^{j})^{num_{i}} \end{aligned}
dp[i][j]===[pi0(1−pi)+pi1(1−pi)+...+pij−1(1−pi)]numi[(pi0+pi1+...+pij−1)(1−pi)]numi(1−pij)numi
等比公式跟得上吧。
那么其坚持了j轮的概率就是
1
−
d
p
[
i
]
[
j
]
1-dp[i][j]
1−dp[i][j]
所以就有第i种硬币坚持了j轮,第j轮只有它留下来的概率:
[
(
1
−
d
p
[
i
]
[
j
]
)
−
(
1
−
d
p
[
i
]
[
j
+
1
]
)
]
∗
Π
k
≠
i
d
p
[
k
]
[
j
]
[(1-dp[i][j])-(1-dp[i][j + 1])]*\Pi_{k\neq i}dp[k][j]
[(1−dp[i][j])−(1−dp[i][j+1])]∗Πk=idp[k][j]
至于为什么要减
1
−
d
p
[
i
]
[
j
+
1
]
1-dp[i][j+1]
1−dp[i][j+1],就是因为,我们要排除他重复的可能性,也就是说这一轮这种硬币活了下来,那么下一轮就让它被全部拿完,否则就会多算,答案会出错。
那么,最后的答案就是把所有的i种硬币j轮赢的概率加起来就行了。至于有多少轮,你自己可以试一下,10,20,30.。。。
3.Code
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int k, t, num[15];
double p[15], dp[15][1005], pai[1005], ans[15];
double qkpow (double x, int y){
double sum = 1.0;
while (y){
if (y & 1)
sum *= x;
x *= x;
y >>= 1;
}
return sum;
}
int main (){
scanf ("%d", &k);
while (k --){
for (int i = 1; i <= 1000; i ++)
pai[i] = 1.0;
scanf ("%d", &t);
for (int i = 1; i <= t; i ++)
ans[i] = 0.0;
for (int i = 1; i <= t; i ++)
scanf ("%d %lf", &num[i], &p[i]);
if (t == 1){
printf ("1.000000\n");
continue;
}
for (int i = 1; i <= t; i ++){
double cnt = 1.0;
dp[i][0] = p[i];
for (int j = 1; j <= 1001; j ++){
cnt *= p[i];
dp[i][j] = qkpow (1.0 - cnt, num[i]);
}
}
for (int i = 1; i <= t; i ++){
for (int j = 1; j <= 1000; j ++){
double cnt = 1.0;
for (int k = 1; k <= t; k ++){
if (k != i)
cnt *= dp[k][j];
}
ans[i] += ((1.0 - dp[i][j]) - (1.0 - dp[i][j + 1])) * cnt;
}
}
for (int i = 1; i < t; i ++)
printf ("%.6f ", ans[i]);
printf ("%.6f\n", ans[t]);
}
return 0;
}
三.Sum up
讲了以上那道经典的概率题目,相信大家一定受益匪浅吧,所以古典概率最好的地方就是所有的元素都是平等的,要充分利用这个条件,考虑周全所有的情况(最好模拟一遍),就可以解题了。