概率与期望
创建时间:2025-12-03
概率
概率的概念
对以一个事件 \(A\),用一个 \(0\) 到 \(1\) 之间的实数 \(P(A)\) (Probability)表示其可能性大小。\(P(A)\) 越大,则事件 \(A\) 发生的可能性越大;反之,可能性越小。特别的,当 \(P(A)=1\) 时,\(A\) 一定发生,将 \(A\) 称为一个必然事件;当 \(P(A)=0\) 时,\(A\) 不可能发生,将 \(A\) 称为一个不可能事件。
定义事件 \(A\) 和 \(B\) 同时发生的概率为 \(P(AB)\),\(A\) 和 \(B\) 至少一个发生的概率为 \(P(A+B)\),由容斥原理知 \(P(A+B)=P(A)+P(B)-P(AB)\)。
称事件 \(A\) 和 \(B\) 为独立事件当且仅当 \(A\) 和 \(B\) 都不影响对方事件的结果;\(A\) 和 \(B\) 为互斥事件当且仅当 \(A\) 和 \(B\) 不可能同时发生,即 \(P(AB)=0\)。
容易发现,对于独立事件 \(A,B\),有
对于互斥事件 \(A,B\),有
概率的应用
概率有关的题目通常顺推解决,因为其起点状态很容易得到。
以 POJ-3071 Football 为例。给定 \(2^n\)(\(n\le7\)) 支球队。每轮将剩余球队编号升序排列,令第一支球队对阵第二支队,第三支球队对阵第四支球队,以此类推,并淘汰败者。给定 \(p_{i,j}\) 表示编号为 \(i\) 的球队击败编号为 \(j\) 的球队的概率,求最有可能获得冠军的球队。
很容易发现比赛过程呈一颗满二叉树,每次在两个节点间决出胜者作为父节点。故若第 \(i\) 轮后 \(j\) 未淘汰,则 \(j\) 可能对阵的球队编号构成一个长度为 \(2^i\) 的区间。
由于 \(n\) 很小,所以可以设 \(dp_{i,j}\) 表示 \(i\) 轮后编号为 \(j\) 的球队未淘汰的概率,直接暴力枚举 \(j\) 对阵的球队转移即可,复杂度 \(O(4^n)\)。
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int MAX_N = 150;
int n;
double p[MAX_N][MAX_N], dp[10][MAX_N];
int main() {
cin.tie(0)->sync_with_stdio(false);
while (true) {
cin >> n;
if (n == -1)
break;
for (int i = 1; i <= 1 << n; i++)
for (int j = 1; j <= 1 << n; j++)
cin >> p[i][j];
fill(dp[0] + 1, dp[0] + (1 << n) + 1, 1);
for (int i = 0; i < n; i++)
for (int j = 1; j <= 1 << n; j++) {
int t = (j - 1 >> i) ^ 1;
dp[i + 1][j] = 0;
for (int k = (t << i) + 1; k <= t + 1 << i; k++)
dp[i + 1][j] += dp[i][j] * dp[i][k] * p[j][k];
}
cout << max_element(dp[n] + 1, dp[n] + (1 << n) + 1) - dp[n] << '\n';
}
return 0;
}
期望
期望的概念
设事件 \(A\) 的结果 \(X=\{x_1,x_2,\cdots,x_n\}\),令 \(P(x)\) 表示结果为 \(x\) 的概率,则定义 \(X\) 的期望(Expectation) \(E(X)=\sum x_iP(x_i)\),也可以认为是 \(X\) 的带权平均值。
根据定义易得:
这也被称作期望的线性性。
注意:期望线性性不要求事件 \(X, Y\) 独立。
期望的应用
期望有关的问题通常倒退求解,因为其终点状态很容易得到。
以 SPOJ - FAVDICE Favorite Dice 为例:有一个有 \(n\) 个面的骰子,要使 \(n\) 个面都至少出现一次,求需要投掷骰子次数的期望。
先考虑问题的简化版:求需要抛硬币抛出正面的期望次数。
设 \(E(X)\) 为其期望次数。显然至少要抛一次。若第一次结果为正面,则不需要再抛;否则,还要再抛 \(E(X)\) 次。故 \(E(X)=1+\frac 1 2 E(X)\),而这是一个一元一次方程!移项解得 \(E(X)=2\)。
回到原问题,设 \(dp_i\) 表示出现 \(i\) 个面的期望次数。显然,\(dp_n=0\)。如果第一次结果为已出现的面,则还要抛 \(dp_i\) 次;否则抛 \(dp_{i+1}\) 次。故 \(dp_i=1+\frac i n dp_i+\frac {n-i} n dp_{i+1}\),解得 \(dp_i=dp_{i+1}+\frac n {n-i}\)。
代码:
#include <iostream>
#include <iomanip>
using namespace std;
const int MAX_N = 1050;
int t, n;
double dp[MAX_N];
int main() {
cin >> t;
while (t--) {
cin >> n;
dp[n] = 0;
for (int i = n - 1; i >= 0; i--)
dp[i] = dp[i + 1] + 1.0 * n / (n - i);
cout << fixed << setprecision(2) << dp[0] << '\n';
}
return 0;
}
期望 DP 的其他题目:
P4550 收集邮票;
P1291 [SHOI2002] 百事世界杯之旅;
POJ - 2096 Collecting Bugs;
HDU - 4405 Aeroplane chess;

浙公网安备 33010602011771号