萌新の概率与期望
不说闲话
概率和期望一直是自己非常薄弱的板块,最早学的时候其实就没有完全听懂。
导致打模拟赛,甚至是 ABC 的时候遇到概率期望相关的题基本上都是绕道走,有时候暴力都打不出来。
重修一下概率论,接下来是做题笔记,后面也会整理成讲题。
P1365 WJMZBMR打osu! / Easy
期望入门题。
题目大意
有一个长度为 \(N\) 的字符串,由 o,x 和 ? 组成。
定义总分数为:字符串中每一段最长连续 o 字串长度的平方和。
? 的含义是该字符不确定,是 o 或 x,各有 \(50 \%\) 的可能性。
求总分数的期望值。
解题思路
很容易想到 dp。
- 设 \(f_i\) 表示前 \(i\) 个字符分数的期望值;
- 设 \(g_i\) 表示前 \(i\) 个字符中以 \(i\) 为最后一个字符的连续
o字串的期望长度。
接下来就可以分类讨论进行状态转移:
\(\begin{cases} s_i=o \begin{cases} f_i= f_{i-1}+ 2\times g_{i-1} +1 \\ g_i=g_{i-1}+1 \end{cases}\\ \\ s_i=x \begin{cases} f_i= f_{i-1} \\ g_i=0 \\ \end{cases}\\ \\ s_i=?\ \ \begin{cases} f_i=f_{i-1}+g_{i-1}+0.5 \\ g_i=0.5\times g_{i-1} + 0.5 \end{cases}\\ \end{cases}\)
时间复杂度 \(O(N)\)。
P4927 [1007] 梦美与线段树
恶心题,式子并不难推,但是代码有一点繁琐。
题目大意
有一颗线段树,每次按节点权值的占比的概率进入该子树,求走过的权值和的期望值。
解题思路
令当前节点为 \(rt\),则不难看出进入 \(rt\) 左子树的期望为:
\(sum_l \times P(l) = sum_l \times \frac {sum_l}{sum_{rt}} = \frac {sum_l^2}{sum_{rt}}\)。
同理,进入 \(rt\) 右子树的期望为:
\(sum_r \times P(r) = sum_r \times \frac {sum_r}{sum_{rt}} = \frac {sum_r^2}{sum_{rt}}\)。
那么就可以得出 \(rt\) 节点走过的权值和的期望值为:\(\frac {sum_l^2+sum_r^2}{sum_{rt}}\)。
下半部分是很好维护的,仅需要维护区间和的线段树即可,而不难看出上半部分就是一个维护区间平方和。
怎么维护呢?考虑每次更新,设增加的数值为 \(\Delta V\)。
那么 \(rt\) 节点的平方和就成为了 \((sum_{rt} + len_{rt} \times \Delta V)^2\)。
考虑完全平方公式展开:
$(sum_{rt} + len_{rt} \times \Delta V)^2 = sum_{rt}^2 + 2 \times len_{rt} \times sum_{rt} \times \Delta V + len_{rt}^2 \times {\Delta V}^2 $。
\(len\) 和 \({len}^2\) 都可以在线段树的 build 阶段维护。
那么我们只需要知道如何维护 \(len_{rt} \times sum_{rt}\),这道题就做完了。
每次更新,\(len_rt \times sum_{rt}\) 就会变成 \(len_{rt} \times (sum_{rt} + len_{rt} \times \Delta V)\)
再拆开来:
\(len_{rt} \times sum_{rt} + len_{rt}^2 \times \Delta V\)。
所以每次更新,\(len_{rt} \times sum_{rt}\) 只需要加上 \(len_{rt}^2 \times \Delta V\) 即可, \(len^2\) 前边已经说过如何维护了。
乍一看,这棵线段树要维护的东西似乎有点多,比较繁琐。
线段树部分代码:
struct Sgt_Tree{
#define lson rt<<1,l,md
#define rson rt<<1|1,md+1,r
int sum[N<<2],sum_2[N<<2];
int len[N<<2],len_2[N<<2];
int len_sum[N<<2],tag[N<<2];
void push_up(int rt,int l,int r){
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
sum_2[rt]=sum_2[rt<<1]+sum_2[rt<<1|1]+sum[rt]*sum[rt];
len_sum[rt]=len_sum[rt<<1]+len_sum[rt<<1|1]+(r-l+1)*sum[rt];
}
void build(int rt,int l,int r){
if(l==r){
sum[rt]=a[l];
len[rt]=1,len_2[rt]=1;
sum_2[rt]=sum[rt]*sum[rt];
tag[rt]=0;
len_sum[rt]=sum[rt];
return;
}
int md=(l+r)>>1;
build(lson);build(rson);
len[rt]=(len[rt<<1]+len[rt<<1|1]+(r-l+1))%mod;
len_2[rt]=(len_2[rt<<1]+len_2[rt<<1|1]+(r-l+1)*(r-l+1))%mod;
push_up(rt,l,r);
}
void make_tag(int rt,int len,int x){
tag[rt]+=x;
sum_2[rt]=sum_2[rt]+2*len_sum[rt]*x;
sum_2[rt]=sum_2[rt]+len_2[rt]*x*x;
len_sum[rt]+=len_2[rt]*x;
sum[rt]+=len*x;
}
void push_down(int rt,int l,int r){
if(tag[rt]){
int md=(l+r)>>1;
make_tag(rt<<1,md-l+1,tag[rt]);
make_tag(rt<<1|1,r-md,tag[rt]);
}
tag[rt]=0;
}
void update(int rt,int l,int r,int L,int R,int x){
if(L<=l&&r<=R){
make_tag(rt,r-l+1,x);
return ;
}
push_down(rt,l,r);
int md=(l+r)>>1;
if(L<=md)update(lson,L,R,x);
if(R>md)update(rson,L,R,x);
push_up(rt,l,r);
}
}Tr;
CF749E Inversions After Shuffle
题目大意
给定一个排列,随机打乱其中一部分,求期望的逆序对个数。
解题思路
考虑对于一个数对 \((a_i,a_j),i<j\),
如果 \((a_i,a_j)\) 被包含在打乱的区间中,则会产生一半的正贡献或一半的负贡献。
\((a_i,a_j)\) 被包含在打乱的区间中的概率为:\(\frac{i\times (n-j+1)}{\frac{1}{2}\times n\times (n+1)} = \frac{2\times i \times (n-j+1)}{n\times (n+1)}\)
那么:
\(a_i>a_j\),则减少的逆序对个数增加 \(\frac{1}{2}\times \frac{2\times i\times (n-j+1)}{n\times (n+1)} = \frac{i\times (n-j+1)}{n\times (n+1)}\)。
同理,\(a_i<a_j\),则减少的逆序对个数减少 \(\frac{1}{2}\times \frac{2\times i\times (n-j+1)}{n\times (n+1)} = \frac{i\times (n-j+1)}{n\times (n+1)}\)。
可以用树状数组维护,建两颗树状数组,一颗计算原序列逆序对个数,另一颗维护上述的减少逆序对的个数,二者相减即可。
这里给出核心代码(树状数组略):
void solve(){
int n;
cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
}
Tr1.init(n),Tr2.init(n);
double cnt=0,ans=0;
for(int i=1;i<=n;i++){
cnt+=Tr1(n)-Tr1(a[i]);
Tr1.add(a[i],1);
}
for(int i=1;i<=n;i++){
ans+=(n-i+1)*(Tr2(n)-Tr2(a[i]));
ans-=(n-i+1)*Tr2(a[i]);
Tr2.add(a[i],i);
}
ans/=n*(n+1);
cout<<fixed<<setprecision(12)<<cnt-ans<<endl;
}
P3317 [SDOI2014] 重建
概率和线性代数的结合。
题目大意
一个图中每条边都有一定概率出现,问生成的图恰好是一颗树的概率。
解题思路
题目要求 \(ans = \sum _{T} \ \ [\ \ \prod _{e \in T} p_e \times \prod _{e \notin T} (1-p_e) \ \ ]\)。
根据矩阵树定理:
定义基尔霍夫矩阵为:无向图的邻接矩阵减去度数矩阵。
那么生成树的个数即为基尔霍夫矩阵的任意 \(k-1\) 阶主子式。
本题求得是概率,那么我们可以简单推广一下:
\(|\text K| = \sum _{T} \prod _{e \in T} p_e\)。
但是注意到矩阵树定理只能求生成图至少是一颗树的概率,怎样才能求出 $\sum _T \prod _{e\notin T (1-p_e)} $ 呢?
考虑:
\(\sum _T \prod _{e\notin T } (1-p_e) = \sum _T \frac {\prod _e (1-p_e)} {\prod _{e\in T} (1-p_e)}\)
\(ans= \prod _e (1-p_e) \times \sum_T \prod _{e \in T} \frac {p_e}{1-p_e}\)
我们直接把无向图的邻接矩阵的边权设为 \(\frac {p_e}{1-p_e}\),那么 \(\sum_T \prod _{e \in T} \frac {p_e}{1-p_e}\) 就可以用矩阵树定理,求 \(n-1\) 阶主子式,时间复杂度 \(O(N^3)\),前半部分可以边读入边计算,最后乘起来,这道题就做完了。
写的时候需要注意精度问题,每次读进概率后加上 \(10^{-8}\) 的 \(eps\)。

浙公网安备 33010602011771号