概率与期望

2024-12-10T20:42:00+08:00 | 7分钟阅读 | 更新于 2024-12-10T20:42:00+08:00

@
概率与期望

第一张在 Qzone 上传的照片,2016 年暑假。 这也是一切的起点吧~

写的很烂。

一. 样本点,样本空间,随机事件

一个随机现象中可能发生的不能再细分的结果成为样本点。所有样本点组成的集合称为样本空间,用 $\Omega$ 表示。

一个随机事件为 $\Omega$ 的子集,由若干样本点组成,用大写字母表示。

对于随机现象的结果 $\omega$ 和随机事件 $A$,称事件 $A$ 发生当且仅当 $\omega\in A$。

二. 概率函数

性质:

  1. 概率函数是事件域到 $[0,1]$ 的映射,即 $\forall A\in\Omega, P(A)\in[0,1]$.
  2. $P(\Omega)=1$
  3. $P(A+B)=P(A)+P(B)-P(AB)$,其中 $A+B=A\cup B, AB=A\cap B$。

三、条件概率:

$P(A|B)$ 指在事件 $B$ 发生的条件下,事件 $A$ 发生的概率,称为条件概率

两个公式:

  1. 概率乘法公式:$P(A\cap B)=P(A)P(B|A)$.
  2. 全概率公式:若一组事件 $A_1,A_2,\cdots,A_n$, $\forall i,j\in[1,n],i\not=j$ 有 $A_i\cap A_j=\phi$ 且 $\bigcup\limits_{i=1}^n A_i=\Omega$,则对于任意事件 $B$ 有 $P(B)=\sum\limits_{i=1}^nP(A_i)P(B|A_i)$.

Bayes 公式:

基本形式:$P(B|A)=\dfrac{P(A|B)P(B)}{P(A)}$

证明:由概率乘法公式,$P(MN)=P(M)P(N|M)$. 则有: $$P(B|A)=\dfrac{P(AB)}{P(A)}$$ $$P(A|B)=\dfrac{P(AB)}{P(B)}$$ 二式相除,即得证。

全概率公式的 Bayes 公式: $$P(A_i|B)=\dfrac{P(A_iB)}{P(B)}=\dfrac{P(A_i)P(B|A_i)}{\sum\limits_{j=1}^nP(A_j)P(B|A_j)}$$ 证明将全概率公式代入上证明即可。

例:某地疫情发病率为 $0.04%$,现用某抗原进行检测。已知患病患者检测结果 $99%$ 为阳性,没患病的人检测结果 $99%$ 为阴性。若某人检测结果为阳性,那他真的得病的概率为多少?

我们设事件 $A$ 指该人得病,事件 $B$ 指检测结果为阳性。则根据题目,有 $P(B|A)=99%,P(B|\overline A)=1%,P(A)=0.04%,P(\overline A)=99.96%$。 所求即为 $P(A|B)$. 根据 Bayes 公式以及全概率公式,有: $$P(A|B)=\dfrac{P(AB)}{P(B)}=\dfrac{P(A)P(B|A)}{P(A)P(B|A)+P(\overline A)P(B|\overline A)}\approx28.4%.$$

独立性

主观地说,事件 $A$ 与事件 $B$ 无关时,则称事件 $A$ 与事件 $B$ 是相互独立的。下面给出定义。

定义: 若在同一概率空间中,若对于多个事件 $A_1,A_2,\cdots,A_n$ 中任意一组事件都有 $P(A_{i_1},A_{i_2},\cdots,A_{i_m})=\prod\limits^m_{k=1}P(A_{i_k})$,则称这些事件 相互独立。 若在同一概率空间中,若对于多个事件 $A_1,A_2,\cdots,A_n$ 中任意两个事件都有 $P(A_iA_j)=P(A_i)P(A_j)$,则称这些事件 两两独立

显然,相互独立的性质要强于两两独立。

四、期望:

随机变量

简单地说,随机变量即为样本空间到实数集的映射。

离散型随机变量

若离散型随机变量 $X$ 的概率分布为 $p_i=P{X=x_i}$ 且 $\sum x_ip_i$ 绝对收敛,则这个值称为 $X$ 的期望,记为 $E(X)$。

连续型随机变量

若连续型随机变量 $X$ 的密度函数为 $f(x)$ 且 $\int_\mathbb{R} f(x)\mathrm{d}x$ 绝对收敛,则这个值称为 $X$ 的期望,记为 $E(X)$。

性质

  • $E(aX+b)=a\cdot E(X) + b$。
  • $E(X+Y)=E(X)+E(Y)$。 若 $X,Y$ 相互独立,则有 $E(XY)=E(X)\cdot E(Y)$。 特别地,上述性质中的独立性并非必要条件。

五、例题

ABC382E

意:一包牌由 $N$ 个卡片组成,其中第 $i$ 个卡片为金卡的概率为 $P_i$,求一包一包地开,开到至少 $X$ 张金卡的期望次数为多少。

分析: 设 $Pc(i,j)$ 表示这一包牌的前 $i$ 开了,获得了 $j$ 张金卡的概率。则易得 $Pc(i,j)=Pc(i-1,j-1)\times(1-P_i)+Pc(i-1,j)\times P_i$。 设 $E(i)$ 表示开到 $i$ 张金卡的期望次数,则 $E(i)=\sum\limits_{j=0}^n E(i-j)\times Pc(n,j)+1$。 然而,我们却注意到 $j=0$ 时,我们会使用 $E_i$ 本身更新 $E_i$ 这显然是不可取的。于是,我们需要进行如下变形: $$E(i)=\sum\limits_{j=1}^n E(i-j)\times Pc(n,j)+E(i)\times Pc(n,0)+1$$ $$(1-Pc(n,0))E(i)=\sum\limits_{j=1}^n E(i-j)\times Pc(n,j)+1$$ $$E(i)=\dfrac{\sum\limits_{j=1}^n E(i-j)\times Pc(n,j)+1}{1-Pc(n,0)}$$

$E(X)$ 即所求。

ABC382E Code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>

using namespace std;

const int MAXN = 5010;

int n, x;
long double p[MAXN], Pc[MAXN][MAXN], E[MAXN];

int main (void) {

    scanf ("%d%d", &n, &x);  Pc[0][0] = 1;
    for (int i = 1; i <= n; i ++) {
        int tmp; scanf ("%d", &tmp); p[i] = tmp * 1.0 / 100;
        Pc[i][0] = Pc[i - 1][0] * (1 - p[i]);
        for (int j = 1; j <= i; j ++)
            Pc[i][j] = Pc[i - 1][j - 1] * p[i] + Pc[i - 1][j] * (1 - p[i]);
    }

    for (int i = 1; i <= x; i ++) {
        for (int j = 1; j <= min (i, n); j ++)
            E[i] += E[i - j] * Pc[n][j];    
        E[i] += 1;
        E[i] /= (1 - Pc[n][0]);
    }

    printf ("%.16Lf", E[x]);

    return 0;
}

Luogu P1365

意:给出一个包含 o, x, ? 的串 $s$,连续的 $n$ 个 o 的贡献为 $n^2$,? 是未填的位置,求贡献的期望。

分析:设 $E_s(i)$ 为以第 $i$ 个字符为结尾的串的期望,$E_l(i)$ 为到第 $i$ 位期望的连续 o 的长度。

则考虑第 $i$ 位字符:

  • 若 $s_i=\mathrm{x}$,则 $E_l(i)=0$, $E_s(i)=E_s(i-1)$。
  • 若 $s_i=\mathrm{o}$,则 $E_l(i)=E_l(i-1)+1$,$E_s(i)=E_s(i-1)+[E_l(i)^2-E_l(i-1)^2]=E_s(i-1)+2E_l(i-1)+1$.
  • 若 $s_i=\mathrm{?}$,此时有 $\dfrac1 2$ 的概率当前位填 $\mathrm o$,$\dfrac1 2$ 的概率当前位填 $\mathrm x$。由离散期望定义易得 $E_l(i)=P(s_i=\mathrm{o})\times (E_l(i-1)+1)+P(s_i=\mathrm{x})\times 0=\dfrac{E_l(i-1)+1}{2}$,同理,$E_s(i)=E_s(i-1)+\dfrac{E_l(i)^2-E_l(i-1)^2+1}{2}=E_s(i-1)+\dfrac{2E_l(i-1)+1}{2}$。

以上,即可 dp 求解。

Luogu P1365 Code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>

using namespace std;

const int MAXN = 3e5 + 10;

int n;
char s[MAXN];
long double El[MAXN], Es[MAXN];

int main (void) {

    scanf ("%d", &n);
    scanf ("%s", s + 1);
    for (int i = 1; i <= n; i ++) {
        if (s[i] == 'x') El[i] = 0, Es[i] = Es[i - 1];
        if (s[i] == 'o') El[i] = El[i - 1] + 1, Es[i] = Es[i - 1] + El[i - 1] * 2 + 1;
        if (s[i] == '?') El[i] = (El[i - 1] + 1) / 2, Es[i] = Es[i - 1] + (El[i - 1] * 2 + 1) / 2; 
    }

    printf ("%.4Lf\n", Es[n]);

    return 0;
}

NOIp2016 tgDay1T3 换教室

意:$v$ 个教室,原定第 $i$ 堂课所在教室为 $c_i$,可以申请更改为 $d_i$,申请通过通过率为 $p_i$,共有 $m$ 次申请次数。教室构成一张无向连通图,体力消耗为每两节课教室之间距离之和。试最小化体力消耗的期望。

分析:自然想到设计 $E2(i,j),E1(i,j)$ 表示前 $i$ 节课已经申请过 $j$ 次,第 $i$ 次换/不换的最小期望。对于第 $i$ 节课,考虑换或是不换。若不换,继续考虑上一节课换/不换带来的贡献,换成功带来的贡献为 $p_{i-1}\times\mathrm{dis}(d_{i-1},c_i)$,失败的带来的贡献为 $(1-p_{i-1})\times\mathrm{dis}(c_{i-1},c_i)$,故 $E1(i,j)=\min{E1(i-1,j)+\mathrm{dis}(c_{i-1},c_i),E2(i-1,j)+p_{i-1}\times\mathrm{dis}(d_{i-1},c_i)+(1-p_{i-1})\times\mathrm{dis}(c_{i-1},c_i)}$。同理,若换,继续考虑第 $i-1$ 是否换,不换则类似于 $E1$ 转移式中第二种情况,换则分四种情况讨论:(成功,成功),(成功,失败),(失败, 成功),(失败, 失败)。最后答案为 $\min\limits_{i=0}^m \min {E1(n,i), E2(n,i)}$。

NOIp2016 tgDay1T3 换教室 Code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int MAXN = 2010, MAXV = 310;

int n, m, v, e;
int c[MAXN], d[MAXN], dis[MAXV][MAXN];
long double E1[MAXN][MAXN], E2[MAXN][MAXN];
long double p[MAXN];

int main (void) {

    memset (dis, 0x3f, sizeof dis);

    scanf ("%d%d%d%d", &n, &m, &v, &e);
    for (int i = 1; i <= n; i ++) scanf ("%d", c + i);
    for (int i = 1; i <= n; i ++) scanf ("%d", d + i);
    for (int i = 1; i <= n; i ++) scanf ("%Lf", p + i);
    for (int i = 1; i <= e; i ++) {
        int u, v, w;
        scanf ("%d%d%d", &u, &v, &w); 
        dis[u][v] = dis[v][u] = min (dis[u][v], w);
    }
    for (int k = 1; k <= v; k ++)
        for (int i = 1; i <= v; i ++)
            for (int j = 1; j <= v; j ++)
                dis[i][j] = min (dis[i][j], dis[i][k] + dis[k][j]);

    for (int i = 0; i <= v; i ++) dis[i][i] = dis[i][0] = dis[0][i] = 0;
    for (int i = 0; i <= n; i ++) for (int j = 0; j <= m; j ++) E1[i][j] = E2[i][j] = 1e9;
    E2[0][0] = E1[0][0] = 0;

    for (int i = 1; i <= n; i ++) {
        E1[i][0] = E1[i - 1][0] + dis[ c[i - 1] ][ c[i] ];   
        for (int j = 1; j <= min (i, m); j ++) {
            E1[i][j] = min (E1[i - 1][j] + dis[ c[i - 1] ][ c[i] ], E2[i - 1][j] + dis[ d[i - 1] ][ c[i] ] * p[i - 1] + (1 - p[i - 1]) * dis[ c[i - 1] ][ c[i] ]);
            E2[i][j] = min (E1[i - 1][j - 1] + dis[ c[i - 1] ][ d[i] ] * p[i] + dis[ c[i - 1] ][ c[i] ] * (1 - p[i]), E2[i - 1][j - 1] + p[i - 1] * p[i] * dis[ d[i - 1] ][ d[i] ] + p[i - 1] * (1 - p[i]) * dis[ d[i - 1] ][ c[i] ] + (1 - p[i - 1]) * p[i] * dis[ c[i - 1] ][ d[i] ] + (1 - p[i - 1]) * (1 - p[i]) * dis[ c[i - 1] ][ c[i] ]);
        }
    }

    long double ans = 1e9;
    for (int i = 0; i <= m; i ++) ans = min ({ans, E1[n][i], E2[n][i]});

    printf ("%.2Lf\n", ans);

    return 0;
}

Luogu P5249

意:$n$ 个人从第 $1$ 个开始轮流朝自己开枪,射中的概率均为 $P_0$,剩下的最后一个人为胜利者。求第 $k$ 个人胜利的概率。特别的,若 $P_0=0$,则认为第一个人胜利。

分析:设 $P(i,j)$ 指剩余 $i$ 人,第 $j$ 人获胜的概率。考虑从第一个人开始,若射中,则剩下 $i-1$ 人,原先的第 $j$ 个人变为 $j-1$,对于 $P(i,j)$ 的贡献为 $P_0\times P(i-1,j-1)$;若没中,则仍有 $i$ 人,由于游戏继续,故当前的第 $j$ 人仍变成第 $j-1$ 人,做出贡献为 $(1-P_0)\times P(i,j-1)$。考虑第 $1$ 个人胜利的情况。此时其为第一个开枪者,绝对不中,而轮到下一个人后,其便成为第 $i$ 个人,故概率为 $(1-P_0)\times P(i,i)$。综上,如下: $$P(i,j)=\begin{cases}P_0\times P(i-1,j-1)+(1-P_0)\times P(i,j-1), & j\ge 2 \ (1-P_0)\times P(i,i) & j=1\end{cases}$$

呈环形结构,考虑变形。设 $P(i,1)=x$,则情况 1 2 联立必可构造出形如 $ax+c=0$ 的方程,解之即可。

由于本题空间较小,故需滚动数组优化。

Luogu P5249 Code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>

using namespace std;

const int MAXN = 1e4 + 10;

int n, k;
long double P0;
long double P[2][MAXN];

int main (void) {

    scanf ("%Lf%d%d", &P0, &n, &k); int N = 1;
    if (P0 < 1e-8) return puts ("0") & 0;
    P[0][1] = 1;
    for (int i = 2; i <= n; i ++) {
        double a = 1, b = 0;
        for (int j = 2; j <= i; j ++) a = a * (1 - P0), b = b * (1 - P0) + P[N ^ 1][j - 1] * P0;
        P[N][1] = (1 - P0) * b / (1 - (1 - P0) * a);
        for (int j = 2; j <= i; j ++) P[N][j] = P[N][j - 1] * (1 - P0) + P[N ^ 1][j - 1] * P0;
        N ^= 1;
    }

    printf ("%.10Lf\n", P[N ^ 1][k]);

    return 0;
}

© 2025 Toorean's Blog

🌱 Powered by Hugo with theme Dream.