[学习笔记] 期望 / 概率相关
我是口胡带诗,好多题没有码,我太懒惰了,难怪码力这么差了。
按照这个 题单 加练一下。强烈推荐在文中提到的题目先思考一下再看我的解析,这挺重要的,得有自己的思考过程和经验。可以看题解也可以直接看我的解法以试图带入我的解题思维体系,希望可以形成思维网。
部分可以期望转概率、概率转频率、频率转计数。
日常生活中,我们每做一件事,都有对它的期望,这里的期望不仅仅只结果的胜负之类,也可以与状态有关。
但在 OI 中,一般指的就是达到结果的期望,最朴素的计算是每次可能结果的概率乘以其结果的总和。
称 \(\rm{E}\)\((x)\) 为 \(x\) 的数学期望值。
设 \(x\)、\(y\) 为任意两个随机变量,则 \(\rm{E}\)\((x+y)=\rm{E}\)\((x)+\rm{E}\)\((y)\)
设 \(x\)、\(y\) 为互相独立的两个随机变量,则 \(\rm{E}\)\((xy)=\rm{E}\)\((x)\times\rm{E}\)\((y)\)
很多的期望题应该使用上述的性质来维护多个值,最后根据式子计算出答案。
upd:还有一个常见的 trick,就是可以将每一步的操作期望拆开计算,最后合起来算贡献,可能好算一些。
板刷前置#
- 关于逆元
模数为质数时 \(x\) 的逆元为 \(x^{p-2}\),否则需要用 exgcd。
线性求逆元:
题目选讲#
那几道普及难度的题没啥必要看,可以用来熟悉概率的定义。一眼秒的也不写了。
CF1042E#
首先按照数值大小排下序。发现只有小于 \(a_{r,c}\) 的格子才有用。遂存下那些格子。
设 \(dp_i\) 为以存下的第 \(i\) 个格子开始走的期望值。有:(\(cnt\) 表示值小于 \(i\) 格子的格子的数量)
搞不了。直接暴力转移会超时,把式子拆开:
对 \({x_i}^2\)、\({y_i}^2\)、\({x_i}\)、\({y_i}\),\({dp_i}\) 做前缀和搞搞就行了。
P1850#
设 \(dp_{i,j,0/1}\) 表示点 \(1\sim i\) 中使用了 \(j\) 次申请,第 \(i\) 次有 / 没有申请的期望值。预处理出 \(dis_{i,j}\) 代表 \(i\) 到 \(j\) 的最短路。
后面部分正常分类讨论即可。
P1365#
\(dp_i\) 表示到了第 \(i\) 位的期望答案。\(len_i\) 表示当前的期望连续长度,\(s_i\) 为 \(1\) 表示字符 o
,为 \(2\) 表示字符 x
,为 \(3\) 表示字符 ?
。
实际上,?
的转移是 x
的转移加上 o
的转移再乘以 \(\frac{1}{2}\) 的结果,因为两者等概率。
CF804D#
注意力惊人的我不难发现可以期望转成计数。
设 \(x\) 所在连通块大小为 \(siz_x\),连接 \(x\)、\(y\) 所在连通块的所有方案中直径之和为 \(sum_{x,y}\),则答案很明显为:
设 \(d_x\) 为 \(x\) 在其连通块内以 \(x\) 为一段的最长的路径长度,\(l_x\) 为连通块内本来的直径长度,可以变成:
\(l_x\)、\(l_y\) 是可以预处理的,但是另外俩东西再套一个最大值咋搞。
上套路,枚举 \(x\) 连通块内的一个点,找到所有 \(y\) 连通块内的 \(d_b + d_a +1 > \max \{l_x,l_y\}\),即 \(d_b \geq \max \{l_x,l_y\} - d_a\),这东西前缀和维护一下,其它的就按 \(\max \{l_x,l_y\}\) 算就可以了。
于是单次查询的时间复杂度是 \(\min \{siz_x,siz_y\}\)。把 \(siz_x\) 按照与 \(\sqrt n\) 的大小关系分个类讨论一下就知道时间复杂度实际上是 \(n \sqrt n\) 的。
P1654#
\(f1_i\) 代表到了第 \(i\) 位的连续长度期望。
\(f2_i\) 代表到了第 \(i\) 位的连续长度平方期望。
注意,\(f2_i \neq {f1_i}^2\),期望性质中没有这一点,显然的:
则答案 \(ans\) 数组有:
(皆为简单推导、展开式子可得。)
P4550#
显然用了 \(x\) 步的花费为 \(\frac{x\times (x+1)}{2}\) 即 \(\frac{x+x^2}{2}\)。求这个式子的期望。
\(f1_i\) 表示收集 \(i\) 个邮票的期望次数。
\(f2_i\) 表示收集 \(i\) 个邮票的期望次数的平方。
化简一下就行了,答案为 \(\frac{f1_n+f2_n}{2}\)。
P3802#
小魔女 /se
最为乐意效劳的一集。
令 \(n=\sum_{i=1}^7 a_i\)。
先考虑前 \(7\) 个。
显然(spent 20 mins😘),概率为:
原因的话,就是无论以什么顺序取,都概率相同,于是排列组合搞一下。
然后,第 \([2,8]\) 的触发概率:
当第 \(1\) 个取了 \(a_1\),有:
(此处的 \(7!\) 指的是首位确定,\(2\sim 8\) 位不定)
当第 \(1\) 个取了 \(a_2\),有:
......
概率总和为:
(化简易得)
发现与 \([1,7]\) 的相同。然后这样的区间共有 \(n-6\) 个,于是上式乘以 \(n-6\) 即为答案期望。
2025省选模拟(2024.12.24)中的T1#
如果上不了了,我还是直接贴图片吧。
不难将该题的期望转为概率。设 \(dp1_{i,j}\) 为 \(i\) 次操作打死 \(j\) 集合内的所有随从的概率,\(dp2_{i,j}\) 为 \(i\) 次操作不打死 \(j\) 集合内的任何随从的概率,\(cnt_i\) 为 \(i\) 集合内元素数量,\(sum_i\) 为 \(i\) 集合内血量之和。
有转移:
具体的,其代表在转移时先打一次,然后再从前面选出几步。
\({dp2}_{i,j}\) 就从 \(dp2_{i-k,j-(j\land -j)}\) 转移过来,从前面的次数中选个 \(k\) 次进行转移,注意枚举顺序应当形似背包,注意判断边界条件。
这里写详细点,此处其实还把概率转了频率再转计数。将概率的计算变为从若干步中选出几步正好打死某个随从 / 正好没打死某个随从。
本来这个时间复杂度是很难通过的(\(1.6\times10^9\),Time limit=4s),但是卡卡能过。
代码还是贴一下,我怕找不到了。
点击查看代码
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;
typedef long long ll;
const int N=17,M=210,MS=((1<<16)|10),mod=998244353;
int n,m,S,cnt[MS],sum[MS],a[N];
ll dp[M][MS],f[M][MS];
ll fac[M],inv[M];
ll qpow(int x,int y)
{
if(y==0)return 1;
ll t=qpow(x,y/2);
if(y%2==0)return t*t%mod;
return t*t%mod*x%mod;
}
void init()
{
cin>>n>>m;
fac[0]=1;
inv[0]=qpow(fac[0],mod-2);
S=1<<n;
for(int i=1;i<=m;i++)
{
fac[i]=fac[i-1]*i%mod;
inv[i]=qpow(fac[i],mod-2);
}
for(int i=1;i<=n;i++)
{
cin>>a[i];
for(int j=0;j<S;j++)
if(j&(1<<i-1))
cnt[j]++,sum[j]+=a[i];
}
}
ll C(int x,int y)
{
if(x<y)return 0;
return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
signed main()
{
init();
dp[0][0]=f[0][0]=1;
for(int i=0;i<=m;i++)
{
for(int j=0;j<S;j++)
{
if(!dp[i][j])continue;
ll w=dp[i][j]*qpow(n-cnt[j],mod-2)%mod;
dp[i+1][j]=(dp[i+1][j]+w)%mod;
for(int k=1;k<=n;k++)
if(!(j&(1<<k-1)))
dp[i+1][j|(1<<k-1)]=(dp[i+1][j|(1<<k-1)]+w*C(i-sum[j],a[k]-1)%mod)%mod;
}
}
for(int j=0;j<S;j++)
{
f[0][j]=1;
for(int i=1;i<=m;i++)
{
int l;
if(j!=0)l=log2((-j)&j)+1;
else l=0;
for(int k=0;k<=min(a[l]-1,i);k++)
f[i][j]=(f[i][j]+f[i-k][j^(1<<l-1)]*C(i,k)%mod)%mod;
}
}
ll ans=0;
for(int i=0;i<S;i++)
if(sum[i]<=m)
ans=(ans+dp[m][i]*f[m-sum[i]][S-1^i]%mod*cnt[i]%mod)%mod;
cout<<ans;
return 0;
}
2025省选模拟(2024.12.24)中的T3#
lyq 学长的解法。
针对每一个局面计算贡献,而不是操作次数。
比如,\(D\) 天中有 \(3\) 天被人为染色,\(1\) 天被自动染色,则称其为一个“局面”。
lyq 学长来了个比较厉害的处理环的方法:将第一次染色的点视为一号点,其它点顺时针排列。
设 \(dp_{i,j}\) 表示有 \(i\) 个点被随机到,有 \(j\) 个点夹在中间被染色的方案数。
显而易见的,答案为:
一部分一部分地解析。
\(dp_{i,j}\frac{1}{C(d-1,i-1)}\) 就当前局面的总数除以选 \(i\) 个节日的总方案数,为频率,即概率。\((i+j)^t\) 是当前局面贡献的值,\(\frac{d}{d-i}\) 代表当前局面存在期望时间。
\(\frac{d}{d-i}\) 是咋算的呢?设 \(f_i\) 表示在 \(d\) 个中选出 \(i\) 个所需要的期望次数。(参考 P1291。)
有:
则从 \(i\) 选到 \(i+1\) 需要的次数的期望值,即存在的期望时间,为 \(\frac{d}{d-i}\)。
\(dp_{i,j}\) 的计算就很平凡了,相当于 \(i\) 个空隙,其中有 \(j\) 个大小恰好为 \(1\),随便搞搞就行,懒得写了,代码可以看 lyq 的。
P3750#
分手是祝愿。
Zeit und Raum trennen dich und mich. 时空将你我分开。
题面与背景毫无关系,狠狠差评。
很难不发现一个按键起到的效果是独一无二的,无法通过别的按键或者组合按键达到同样的效果。
所以,当前局面下最优的答案就是从后往前按,如果当前按钮是亮的那就按下。
操作多了一点的都是因为操作者整活,连续偶数次按了一个按键,效果抵消,没啥用。
所以就可以设 dp 状态了。设 \(dp_i\) 表示从还需 \(i\) 次变为还需 \(i-1\) 次所需的期望次数。
显而易见的(spent 15mins🥵),转移方程:
解释一下。\(\frac{i}{n}\) 的概率直接按对,如果按错,就需要再按一次那个按钮,即从 \(i+1\) 到 \(i\) 的期望步数再加一步,然后还要再从 \(i\) 到 \(i-1\),即 \(dp_i\)。
整理一下就是:
然后搞定了。x
P3412#
吗的,仓鼠都有 meizi 了。
考虑固定一个终点,使其为树的根节点。
计算此时的期望。
设 \(f_x\) 表示从 \(x\) 到 \(x\) 的父亲节点期望需要的步数,\(son_x\) 为 \(x\) 的儿子集合,有:
整理一下:
设 \(g_x\) 表示从 \(x\) 的父亲节点到 \(x\) 期望需要的步数,\(fa_x\) 为 \(x\) 的父亲节点,有:
整理一下:
然后贡献很好算了。
P3830#
第一问很好算。一次展开会导致深度之和加二,叶子节点数量加一,随便转移一下再算就行了。出题人给了 50 pts 的巨额分数。
第二问中整棵树的深度其实就是叶子节点深度的最大值。
设 \(g_{i,j}\) 表示有 \(i\) 个叶子节点,树的深度大于等于 \(j\) 的概率。
枚举左右子树大小进行转移,有:
\(g_{k,j-1}+g_{i-k,j-1}-g_{k,j-1}\times g_{i-k,j-1}\) 这部分是容斥。\(\frac{1}{i-1}\) 是一棵有 \(i\) 个叶子节点的树,左子树有 \(k\) 个叶子节点的概率。
这里解释一下后面那一句话。
首先考虑一棵有 \(i\) 个叶子节点的树,左子树有 \(k\) 个叶子节点的方案数,即在除了根节点之外的 \(i-2\) 次展开中,有 \(k-1\) 次属于左子树,为 \(C_{i-2}^{k-1}\),即 \(\frac{(i-2)!}{(k-1)!(i-k-1)!}\)。
考虑一个有 \(i\) 个叶子节点的树有多少种可能,显然是 \((i-1)!\)(第一次展开只有一个点可选,第二次有两个点,第三次有三个......第 \(i-1\) 次有 \(i-1\) 个)。
所以,再将选择展开次数的方案数乘以得到了展开次数后的排列方法,即 \(\frac{(i-2)!}{(k-1)!(i-k-1)!}\times (i-1)!\times (i-k-1)!\)(左、右子树的排列方案数都要乘),即 \((i-2)!\)。
也就是说,无论左子树有几个节点,生成出这样的树的方案数都是 \((i-2)!\),与 \(k\) 无关。
再用 \((i-2)!\) 除以总方案数 \((i-1)!\) 即为 \(\frac{1}{i-1}\)。
故转移成立。
答案显然为:
不用乘以 \(i\),因为定义是大于等于 \(i\),加一起正好抵消了,反演容斥啥的都不用,方便转移、容易计算,精妙绝伦的设计!!
P4562#
定义关键数字为满足 \([l,r]\) 内没有任何它的因数(除了其本身)的数。
有结论:一个检查顺序 \(p\) 的 \(t(p)\) 等于最后一个关键数字的位置。
下面给出证明:
设最后一个关键数字为 \(x\),其位置在 \(i\),则假设结论错误,有 \([i+1,r]\) 中的某个位于 \(j\) 的数在 \([1,i]\) 之内并无因数。
又 \(x\) 为最后一个关键数字,故 \(p_j\) 不是关键数字,其在 \([i+1,r]\) 中有一个除了自己本身的因数。
发现,\([i+1,r]\) 中必有一个关键数字。因为如果 \(p_j\) 的一个因数是关键数字,但是位于 \([1,i]\) 中,则不需要考虑 \(p_j\)(会被那个因数淘汰)。
故假设不成立,自相矛盾,结论正确。
然后问题变成:假设从 \(n\) 个数中随机选出 \(k\) 个(设 \(k\) 个关键数字),最后选出的数的期望位置?
\(k\) 个关键数字将整个区间分成 \(k+1\) 个小段,则一个非关键数字排在最后一个小段的概率是 \(\frac{1}{k+1}\)。
所以非关键数字排在最后一个小段的期望个数是 \(\frac{n-k}{k+1}\)。
则最后一个关键数字的期望位置是 \(n-\frac{n-k}{k+1}\)。
则答案为 \(n!\times (n-\frac{n-k}{k+1})=(n+1)!\frac{k}{k+1}\)。
CF398B#
我草,这题被我秒了,何德何能啊,难不成加练是有效果的??
设 \(dp_{i,j}\) 表示还有 \(i\) 行,\(j\) 列需要涂色,达到目标状态的期望步数。
不难发现,实际上具体的是哪一些列,哪一些行是不影响答案的。
显而易见的,转移:
整理一下就行了。
深刻思考后,我发现这题难度评高了,这并不属于我的真实水平,加练。
CF248E#
设 \(dp_{i,j}\) 表示第 \(i\) 个货架有 \(j\) 个未被试吃过的蜜罐的概率。
不难发现一次操作只影响 \(u\) 的 \(dp_{u,j}\) 值,\(v\) 是不被影响的。
于是每次操作都跑 dp,枚举拿走了的尚未被品尝的蜜罐个数 \(q (0\le q\le k)\),设货架 \(i\) 有 \(now_i\) 个蜜罐,有:
细节很几把多。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义