概率与期望
概率与期望
概率论
事件的运算及概率
-
包含:,发生 时必然发生 ,发生 时不一定发生 。
-
并(和)事件:, 发生或 发生或两者都发生。
-
交(积)事件:, 和 同时发生。
-
差事件:, 发生但 不发生, 表示 的对立事件。
-
互斥事件:, 和 不能同时发生。
-
对立(逆)事件:, 发生时 不发生, 发生时, 不发生。
-
独立事件:
发生与否不影响 的概率,反之亦然。
- 若 独立,则 、、 也相互独立。
- 若 相互独立,那么
- 两两独立(但逆命题不成立)
- 。
-
德摩根律:
$$\overline{A\cup B}=\overline{A}\cap\overline{B}\\ \overline{A\cap B}=\overline{A}\cup\overline{B} $$ -
加法公式(容斥原理):
-
减法公式:
-
对立事件概率:
条件概率与乘法公式
-
条件概率:在 已发生下 的概率。
-
乘法公式:
全概率公式与贝叶斯公式(包括在 NOI 大纲内但大概率 useless)
-
全概率公式( 为完备事件组):
-
贝叶斯(逆概)公式:
离散型随机变量(一维)
离散型随机变量是指取值为可列(通常是有限或可数无限)集合中某些具体数值的随机变量。
分布列
随机变量 可取值:
各取值对应的概率为:
分布函数
重要性质 离散型一维随机变量的分布函数可视为前缀和):。
数学期望
若 ,则
性质:
-
。
-
-
若 独立,则 。
方差
性质:
- 。
- ,其中
为协方差。 - 若独立,则 ,因此 。
常见分布
【0–1 分布(伯努利分布)】
进行一次独立试验,成功的概率为 ,失败的概率为 。(即 的二项分布)
| 记作 | 分布列 | 数学期望 | 方差 |
|---|---|---|---|
【二项分布】
进行 次独立试验,每次成功的概率为 ,失败的概率为 。
| 记作 | 分布列 | 数学期望 | 方差 |
|---|---|---|---|
【几何分布】
进行独立试验,直到第一次成功为止;成功的概率为 ,失败的概率为 。
| 记作 | 分布列 | 数学期望 | 方差 |
|---|---|---|---|
【超几何分布】
从 个物体中抽取 个物体,其中有 个是成功的, 个是失败的。
| 记作 | 分布列 | 数学期望 | 方差 |
|---|---|---|---|
| $P\{X=k\}=\dfrac{\binom{K}{k}\binom{N-K}{n-k}}{\binom{N}{n}}$ |
概率与期望 DP
与组合数 DP 类似,只是在 DP 转移时结合概率或期望的计算。常见有后效性方程,需要移项或高斯消元处理。
【例题 1】Jerry's Protest(纯概率论应用)
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n; cin>>n;
vector<int> a(n);
for(int i=0;i<n;i++) cin>>a[i];
sort(a.begin(), a.end());
// 赢 a[i]-a[j] 的概率
unordered_map<int, double> p;
for(int i=0;i<n;i++)
for(int j=0;j<i;j++)
p[a[i]-a[j]] += 2.0/(n*(n-1));
// 后手前两把总和的概率
unordered_map<int, double> q;
for(auto i : p)
for(auto j : p)
q[i.first+j.first] += i.second*j.second;
double ans = 0;
for(auto i : p)
for(auto j : q)
if(i.first>j.first) ans += i.second*j.second;
cout<<fixed<<setprecision(10)<<ans<<'\n';
}
【例题 2】ABC326E(普通期望 DP)
-
状态: 为当前值为 时后续期望工资。
-
初值:。因为此时无法掷出满足 的 。
-
目标:。
-
转移:$\displaystyle E(x)=\sum_{y=x+1}^{n}\frac{1}{n}\big(A_y+E(y)\big)$。
需要从 到 进行计算,计算过程中对 动态维护一个后缀和即可 解决。
#include <bits/stdc++.h>
#include <atcoder/modint>
using namespace std;
int main(){
cin.tie(nullptr)->sync_with_stdio(false);
cin.exceptions(cin.failbit);
using mint = atcoder::modint998244353;
int n; cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;i++) cin>>a[i];
vector<mint> E(n+1);
mint suf = 0;
for(int i=n;i>=0;i--){
E[i] = suf;
suf += (a[i]+E[i])/n;
}
cout<<E[0].val()<<'\n';
}
【例题 3】ABC360E(期望 DP 线性递推)
状态设计
- 代表当进行了 次交换后,黑球位置的期望值。
初始状态
所求结果
转移方程
独立均匀地随机选择两个整数,总方案数 。设黑球当前位置为 ,选择到的两个整数为 。
-
其中 的方案数为 ;
$$\frac{(N-1)^2+1}{N^2}\,E(x-1)\ \longrightarrow\ E(x). $$
的方案数为 。
这两种情况都不会对黑球的位置产生影响 ,即: -
而对于剩余的种情况 ,黑球位置会被等概率交换到 中除 以外的其他位置
因此:
$$\frac{2N-2}{N^2}\cdot \frac{1}{N}\! \left(\sum_{i=1}^{N - 1} i - E(x-1)\right)\ \longrightarrow\ E(x). $$
将两部分相加并整理,得到
$$E(x) = \frac{(N-1)^2+1}{N^2}\,E(x-1) + \frac{2N-2}{N^2}\cdot \frac{1}{N-1}\! \left(\sum_{i=1}^{N} i - E(x-1)\right). $$因为 ,继续化简:
$$\begin{aligned} E(x) &= \frac{(N-1)^2+1}{N^2}\,E(x-1) + \frac{2N - 2}{N^2}.\frac 1 {N - 1}\!\left(\sum_{i = 1} ^ N i - E(x-1)\right) \\ &= \frac{(N-2) \,E(x-1) + N + 1}{N} \end{aligned} $$最终递推式:
#include <bits/stdc++.h>
#include <atcoder/modint>
using namespace std;
int main(){
cin.tie(nullptr)->sync_with_stdio(false);
cin.exceptions(cin.failbit);
using mint = atcoder::modint998244353;
int n, k; cin>>n>>k;
vector<mint> E(k+1);
E[0] = 1;
for(int i=1;i<=k;i++) E[i] = ((n-2)*E[i-1]+n+1)/n;
cout<<E[k].val()<<'\n';
}
【例题 4】ABC382E(概率 DP + 期望 DP + 移项消后效性)
概率部分:先求每个卡包爆出 张稀有卡的概率(简单概率 DP)
- 状态设计: 表示拆到第 张卡片,累计爆出 张稀有卡的概率。
- 初始状态:
- 状态转移:$\displaystyle P_{i,j}=p_i\,P_{i-1,j-1} + (1-p_i)\,P_{i-1,j}$
- 所求结果:(第 张拆完后的各个 的概率分布)
然后处理问题所要求的期望部分,枚举每拆一个卡包获取到稀有卡的数量,简单期望 DP 处理:
期望部分:每拆一个卡包获得稀有卡的数量(简单期望 DP)
-
状态设计: 表示从 张卡片开始拆包,直到至少有 张卡片的期望步数。
-
初始状态:
-
原始转移式:
$$E_i=\sum_{j=0}^{n} P_{n,j}\,\big(E_{\min(x,i+j)}+1\big) $$
注意:当 时出现自依赖项,可移项消环。
-
移项后的等价式:
$$\begin{aligned} E_i &= \sum_{j=1}^{n} P_{n,j}\,\big(E_{\min(x,i+j)}+1\big) + P_{n,0}\,(E_i+1) \\ (1-P_{n,0})\,E_i &= \sum_{j=1}^{n} P_{n,j}\,\big(E_{\min(x,i+j)}+1\big) + P_{n,0} \\ E_i &= \frac{\displaystyle \sum_{j=1}^{n} P_{n,j}\,\big(E_{\min(x,i+j)}+1\big) + P_{n,0}} {1-P_{n,0}} \; . \end{aligned} $$ -
所求结果:
#include <bits/stdc++.h>
using namespace std;
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
cin.exceptions(cin.failbit);
int n,x;
cin>>n>>x;
vector<int> a(n);
for(int i=0;i<n;i++) cin>>a[i];
vector<double> p(n);
for(int i=0;i<n;i++) p[i] = a[i]/100.0;
vector<vector<double>> P(n+1, vector<double>(n+1));
P[0][0] = 1;
for(int i=0;i<n;i++)
{
for(int j=0;j<=n;j++)
{
if(j!=n) P[i+1][j+1] += P[i][j]*p[i];
P[i+1][j] += P[i][j]*(1-p[i]);
}
}
vector<double> E(x+1);
for(int i=x-1;i>=0;i--)
{
E[i] += P[n][0];
for(int j=1;j<=n;j++) E[i] += P[n][j]*(E[min(x, i+j)]+1);
E[i] /= (1-P[n][0]);
}
cout<<fixed<<setprecision(10)<<E[0]<<'\n';
}
【例题 5】ABC411E (分布函数转化)
目标与记号
-
设 表示所有骰子掷出后最大值为 的概率,则答案:
其中 枚举所有可能出现的点数。
思路
考虑如何求 时,显然所有点数 值都不能出现,这很好解决。其次还需要剩下的点数中至少有一个点数为 ,解决这个限制比较困难。
考虑使用分布函数进行转化。设分布函数为:
由分布函数性质:
因而
计算
注意到求 与求 的差别,相当于把“剩下的点数中至少有一个点数为 ”这个限制去除,这样问题就非常容易解决了。
我们维护一下每个骰子的点数 的面的数量(记为 ),则有:
将所有骰子的点数进行从大到小的排序,计算完一个点数后就更新一下所有包含这个点数的骰子的 ,并且同步更新上式的值即可。
#include <bits/stdc++.h>
#include <atcoder/modint>
using namespace std;
using ll = long long;
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
cin.exceptions(cin.failbit);
using mint = atcoder::modint998244353;
int n;
cin>>n;
vector<array<int, 6>> a(n);
for(int i=0;i<n;i++)
for(int j=0;j<6;j++)
cin>>a[i][j];
map<int, vector<int>> pos;
for(int i=0;i<n;i++)
for(int j=0;j<6;j++)
pos[a[i][j]].push_back(i);
vector<pair<int, vector<int>>> v(pos.rbegin(), pos.rend());
mint prod = 1;
vector<int> cnt(n, 6);
map<int, mint> f;
for(auto& [x, w] : v)
{
f[x] = prod;
for(auto i : w)
{
prod /= mint(cnt[i])/6;
cnt[i]--;
prod *= mint(cnt[i])/6;
}
}
reverse(v.begin(), v.end());
mint ans = 0;
for(size_t i=0;i<v.size();i++)
{
if(i==0) ans += v[i].first*f[v[i].first];
else ans += v[i].first*(f[v[i].first]-f[v[i-1].first]);
}
cout<<ans.val()<<'\n';
}
【例题 6】ABC412F Socks 4(观察性质消后效性)
设
期望题目首先考虑期望 DP。注意到题目中仅有“高桥手中的袜子的颜色”这一个变量,因此可简单设计状态:
表示当高桥手中拥有颜色为 的袜子时,还需要的期望抽取次数。
考虑如何进行状态转移:当高桥手中拥有颜色为 的袜子时,他从抽屉柜中随机取出一只袜子,耗费一次抽取次数。接下来可能的情况有:
- 取出颜色为 的袜子,此时操作终止,后续期望抽取次数为 。
- 取出颜色不为 的袜子(设颜色为 ),此操作的概率为 。接下来他会选择能使未来期望抽袜次数最小化的那只袜子放回,后续期望抽取次数为。
因此可得状态转移方程:
$$E(x)=1+\sum_{y\ne x}\frac{A_y}{S}\min\!\big(E(x),E(y)\big). $$这是一个自依赖且自依赖包括在 中的状态转移方程,乍一看似乎无法直接求解,然而我们可以感性理解一下:越大,越容易一抽即中,因此 越小。故状态转移方程即可化为:
$$E(x)=1+\sum_{\substack{y\ne x\\ A_y\le A_x}}\frac{A_y}{S}E(x) +\sum_{\substack{y\ne x\\ A_y>A_x}}\frac{A_y}{S}E(y). $$移项可得:
$$\boxed{\,E(x)= \frac{ S+\displaystyle\sum_{\substack{y \neq x\\ A_y>A_x}} A_y E(y) } { S-\displaystyle\sum_{\substack{y \neq x\\ A_y\le A_x}} A_y }\, }. $$对 排序(设按 递增把颜色重新编号为 ),则上式化为前后缀可维护的形式:
$$\,E(x)=\dfrac{S+\sum_{y实现要点:
-
先按 升序排序;
-
维护 的前缀与 的后缀,从大到小(或小到大)依次求解 ;
-
目标为所给颜色 的 。
#include <bits/stdc++.h>
#include <atcoder/modint>
using namespace std;
using ll = long long;
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
cin.exceptions(cin.failbit);
using mint = atcoder::modint998244353;
int n, c;
cin>>n>>c;
vector<int> a(n+1);
for(int i=1;i<=n;i++) cin>>a[i];
mint sum = accumulate(a.begin()+1, a.end(), mint(0));
a[c]++;
vector<int> o(n+1);
iota(o.begin()+1, o.end(), 1);
sort(o.begin()+1, o.end(), [&](int i, int j) { return a[i]<a[j]; });
vector<mint> E(n+1);
mint pre=0, suf=0;
for(int i=1;i<=n;i++) pre += a[o[i]];
for(int i=n;i>=1;i--)
{
pre -= a[o[i]];
E[i] = (sum+suf)/(sum-pre);
suf += a[o[i]]*E[i];
if(o[i]==c)
{
cout<<E[i].val()<<'\n';
break;
}
}
}
随机游走模型
线性随机游走(U575231 跃迁)
状态设计
:从位置 跃迁到 的一步期望时长。
初始状态
所求
转移方程
(分子前半是先回到 再到 进而到 ;后半是直接到 。)
移项消后效性
树上随机游走
给定一棵有根树,树的某个结点上有一个硬币,在某一时刻硬币会等概率地移动到邻接结点上,问硬币移动到邻接结点上的期望距离。
需要用到的定义
-
树
-
度
-
边权
-
父结点 、根
-
子集 、兄弟集
一、向父结点走的期望距离
设 为从 走到其父 的期望距离( 不存在),则有。
$$f(u)=\frac{\,w(u,p_u)+\displaystyle\sum_{v\in \texttt{son}_u}\bigl(w(u,v)+f(v)+f(u)\bigr)}{d(u)} $$分子前半表示直接走向父结点,后半表示先走到子结点、从子结点回到 ,再到父结点;
分母 表示从 以等概率走向任一邻接点。
化简如下
$$\begin{aligned} f(u) &=\frac{\,w(u,p_u)+\displaystyle\sum_{v\in\texttt{son}_u}\bigl(w(u,v)+f(v)+f(u)\bigr)}{d(u)}\\[4pt] &=\frac{w(u,p_u)+\displaystyle\sum_{v\in\texttt{son}_u}\bigl(w(u,v)+f(v)\bigr)+(d(u)-1)f(u)}{d(u)}\\[4pt] &=\,w(u,p_u)+\sum_{v\in\texttt{son}_u}\bigl(w(u,v)+f(v)\bigr)\\[4pt] &=\sum_{(u,t)\in E} w(u,t)\;+\!\!\sum_{v\in\texttt{son}_u} f(v). \end{aligned} $$-
对于叶子结点 :。
-
当树上所有边的边权都为1时,上式可化为:
即 子树的所有结点的度数和,也即 子树大小的两倍 (每个结点连向其父亲的边都有且只有一条,除 与 之间的边只有 点度数的贡献外,每条边会产生 点度数的贡献)。
向子结点走的期望距离
设 为从 到其子结点 的期望距离。
$$g(u)=\frac{\,w(p_u,u)+\bigl(w(p_u,p_{p_u})+g(p_u)+g(u)\bigr)+ \displaystyle\sum_{s\in\texttt{sibling}_u}\bigl(w(p_u,s)+f(s)+g(u)\bigr)}{d(p_u)}. $$分子中的第一部分代表直接走向了子结点 ,第二部分代表先走向了父结点再由父结点走回来然后再向 结点走,第三部分代表先走向 结点的兄弟结点再由其走回来然后再向 结点走;分母 代表从 结点走向其任何邻接点的概率相同。
化简如下
$$\begin{aligned} g(u) &= \frac{ w(p_u,u) + \bigl(w(p_u,p_{p_u})+g(p_u)+g(u)\bigr) + \sum_{s\in \mathrm{sibling}_u} \bigl(w(p_u,s)+f(s)+g(u)\bigr)}{d(p_u)} \\[2pt] &= \frac{ w(p_u,u) + w(p_u,p_{p_u}) + g(p_u) + \sum_{s\in \mathrm{sibling}_u} \bigl(w(p_u,s)+f(s)\bigr) + (d(p_u)-1)g(u)}{d(p_u)} \\[2pt] &= w(p_u,u) + w(p_u,p_{p_u}) + g(p_u) + \sum_{s\in \mathrm{sibling}_u} \bigl(w(p_u,s)+f(s)\bigr) \\[2pt] &= \sum_{(p_u,t)\in E} w(p_u,t) + g(p_u) + \sum_{s\in \mathrm{sibling}_u} f(s) \\[2pt] &= \sum_{(p_u,t)\in E} w(p_u,t) + g(p_u) + \bigl(f(p_u) - \sum_{(p_u,t)\in E} w(p_u,t) - f(u)\bigr) \\[2pt] &= g(p_u) + f(p_u) - f(u). \end{aligned} $$初始状态为 。
参考实现(无权树)
vector<int> G[MAXN];
void dfs1(int u, int p) {
f[u] = G[u].size();
for (auto v : G[u]) {
if (v == p) continue;
dfs1(v, u);
f[u] += f[v];
}
}
void dfs2(int u, int p) {
if (u != root) g[u] = g[p] + f[p] - f[u];
for (auto v : G[u]) {
if (v == p) continue;
dfs2(v, u);
}
}
【题目清单】
概率论
- P8804 [蓝桥杯 2022 国 B] 故障(贝叶斯公式)
- P6154 游走(DAG DP)
- CF626D Jerry's Protest
- ABC380G
- P2221 [HAOI2012] 高速公路(线段树维护期望)
概率 DP
- CF148D Bag of mice
- CF167B Wizards and Huge Prize(背包+概率 DP)
- ABC382E Expansion Packs(概率 DP + 期望 DP + 移项消后效性)
- P4284 [SHOI2014] 概率充电器(树上概率 DP)
- P12292 [蓝桥杯 2024 国 Java A] 斗蛐蛐(有后效性)
- P12293 [蓝桥杯 2024 国 Java A] 合并小球
期望 DP
- CF1925D Good Trip
- ABC326E Revenge of "The Salary of AtCoder Inc."
- ABC360E Random Swaps of Balls
- ABC402E Payment Required(推荐,背包+状压+期望 DP)
- ABC411E E [max](分布函数)
- ABC412F Socks 4(观察性质消后效性)
- P1850 [NOIP 2016 提高组] 换教室
- P2473 [SCOI2008] 奖励关(状压+期望 DP)
- P4206 [NOI2005] 聪聪与可可
- P2081 [NOI2012] 迷失游乐园(树上期望 DP)
- P3239 [HNOI2015] 亚瑟王
随机游走
- U575231 跃迁(线性随机游走)
- CF1823F Random Walk(树上随机游走)
- CF2040E Control of Randomness(树上随机游走)
- P3211 [HNOI2011] XOR和路径(高斯消元)
- P3232 [HNOI2013] 游走(高斯消元)
- P6899 [ICPC 2014 WF] Pachinko(高斯消元)
一些 XCPC 的题目
XCPC 经常出概率与期望 DP(由于 Codeforces 的限制,Gym 的题目需要复制链接粘贴到地址栏打开):
- 2021 ICPC 昆明区域赛 B. Blocks(状压+期望 DP)
- 2023 CCPC 湘潭邀请赛 F. Timaeus(移项消后效性)
- 2024 CCPC 郑州分站赛 K. Brotato(观察性质消后效性)
- 2024 CCPC 哈尔滨分站赛 E. Marble Race(期望 DP)
京公网安备11010802045784号