概率与期望
1
定义
概率,就是某个随机事件出现的可能性大小。
若\(X\)是一个离散型的随机变量,可能值为$x_1,x_2,\cdots \(,对应的概率分别为\)p_1,p_2,\cdots $,那么它的期望值为
期望的线性性
由此可以得到:
期望的另一个结论
当随机变量\(X\)和\(Y\)独立时,\(E(XY)=E(X)E(Y)\)。
一些题目
Game on tree
题意
https://codeforces.com/contest/280/problem/C
sol
考虑对于一个点\(i\)来说,如果它有\(1\)的贡献,当且仅当它在所有祖先被选之前选了,概率是\(\frac{1}{dep_i}\),所以一个点贡献的期望也是\(\frac{1}{dep_i}\)。
由期望的线性性可知,答案就是所有点贡献的期望的和,即所有点的\(\frac{1}{dep_i}\)的和。
Forest game
题意
https://codeforces.ml/gym/101234/problem/D
给定一棵\(n\)个节点的树,然后每次进行以下操作直到没有点
随机均匀地选择一个节点,然后将答案加上这个节点所在树的大小,最后删除这个点。
sol
考虑删除\(u\)点时如果\(v\)点对其有\(1\)的贡献当且仅当\(u\)是\(u\)到\(v\)路径上第一个被删除的点,概率为\(\frac{1}{dist(u,v)+1}\)。
所以答案即对于每一对\((u,v)\),都统计一遍贡献即可,即:
考虑点分治+FFT计算出每种长度的路径出现了多少次,然后算一下答案即可。
int n;
struct CP
{
double x,y;
inline CP(double X=0,double Y=0):x(X),y(Y){}
inline CP operator +(const CP &A)const{return CP(x+A.x,y+A.y);}
inline CP operator -(const CP &A)const{return CP(x-A.x,y-A.y);}
inline CP operator *(const CP &A)const{return CP(x*A.x-y*A.y,x*A.y+y*A.x);}
inline CP operator /(const CP &A)const{double tt=A.x*A.x-A.y*A.y;return CP((x*A.x+y*A.y)/tt,(y*A.x-x*A.y)/tt);}
}f[888888];
int tr[888888],tf;
int inv[111111],Finv[111111],F[111111];
vector<int>e[111111];
int siz[111111],vis[111111];
int fa[111111];
int Mx_s[111111];
int sub[111111];
int allmxl,mxl;
int rt,alt;
int ans;
vector<int>all,cnt;
inline void add(int &x,int y)
{
x+=y;x>=mod?x-=mod:1;
}
inline void dec(int &x,int y)
{
x-=y;x<0?x+=mod:1;
}
inline void tpre(int n)
{
if(tf==n) return;tf=n;
R(i,0,n-1) tr[i]=(tr[i>>1]>>1)|((i&1)?n>>1:0);
}
/*
void FFT(CP *f,int rev,int n)
{
tpre(n);
R(i,0,n-1) if(i<tr[i]) swap(f[i],f[tr[i]]);
for(int p=2;p<=n;p<<=1)
{
int len=p>>1;
CP tG(cos(2*Pi/p),sin(2*Pi/p));
if(!rev) tG.y*=-1;
for(int k=0;k<n;k+=p)
{
CP buf(1,0);
for(int l=k;l<k+len;l++)
{
CP tt=buf*f[len+l];
f[len+l]=f[l]-tt;
f[l]=f[l]+tt;
buf=buf*tG;
}
}
}
if(!rev)
{
R(i,0,(n-1)) f[i].x=f[i].x/n/2.0,f[i].y=f[i].y/n/2.0;
}
}
*/
void FFT(CP *f,int rev,int n)
{
tpre(n);
R(i,0,n-1) if(i<tr[i]) swap(f[i],f[tr[i]]);
for(int p=2;p<=n;p<<=1)
{
int len=p>>1;
CP tG(cos(2*Pi/p),sin(2*Pi/p));
if(!rev) tG.y*=-1;
for(int k=0;k<n;k+=p)
{
CP buf(1,0);
for(int l=k;l<k+len;l++)
{
CP tt=buf*f[len+l];
f[l+len]=f[l]-tt;
f[l]=f[l]+tt;
buf=buf*tG;
}
}
}
if(!rev)
{
R(i,0,(n-1)) f[i].x=f[i].x/n,f[i].y=f[i].y/n;
}
}
int solve(vector<int>&v,int n)
{
int m=1;
for(;m<=n;m<<=1);m<<=1;
//printf("m:%lld n:%lld\n",m,n);
//for(int x:v) printf("x:%lld ",x);
//puts("");
R(i,0,m) f[i]=CP(0.0,0.0);
R(i,0,n) f[i].x=(double)v[i];
FFT(f,1,m);
R(i,0,m-1) f[i]=f[i]*f[i];
FFT(f,0,m);
/*
puts("f:");
R(i,0,n<<1) printf("x:%.8lf:",f[i].x);
puts("");
*/
R(i,1,n) f[i<<1].x-=(double)v[i];
R(i,0,n<<1) v[i]=(int)(f[i].x+0.4999999);
int ret=0;
//R(i,0,n<<1) printf("i:%lld v[i]:%lld inv[i]:%lld\n",i,v[i],inv[i+1]);
R(i,0,n<<1) add(ret,v[i]*inv[i+1]%mod);
return ret;
}
void dfs3(int u,int f,int d)
{
ckmax(mxl,d);
if(d==(int)cnt.size()) cnt.pb(1);else ++cnt[d];//qwq
if(d==(int)all.size()) all.pb(1);else ++all[d];
for(int v:e[u])
{
if(vis[v]||v==f) continue;
dfs3(v,u,d+1);
}
}
void dfs2(int u,int f)
{
sub[u]=1;
for(int v:e[u])
{
if(vis[v]||v==f) continue;
dfs2(v,u);
sub[u]+=sub[v];
}
}
void dfs1(int u,int f)
{
Mx_s[u]=0,siz[u]=1;
for(int v:e[u])
{
if(vis[v]||v==f) continue;
dfs1(v,u);
siz[u]+=siz[v];
ckmax(Mx_s[u],siz[v]);
}
ckmax(Mx_s[u],alt-siz[u]);
rt=(Mx_s[u]<Mx_s[rt]||(Mx_s[u]==Mx_s[rt]&&u<rt))?u:rt;
}
void dfs0(int u)
{
dfs2(u,0);
Mx_s[rt=0]=inf;
alt=sub[u];
dfs1(u,0);
//printf("%lld %lld %lld\n",Mx_s[1],Mx_s[2],Mx_s[3]);
//printf("rt:%lld\n",rt);
vis[rt]=1;
u=rt;
for(int v:e[u]) if(!vis[v]) dfs0(v);
all.clear();
allmxl=0,all.pb(1);
for(int v:e[u]) if(!vis[v])
{
cnt.clear();
mxl=0;cnt.pb(0);
dfs3(v,u,1);
//printf("mxl:%lld\n",mxl);
cnt.resize(cnt.size()<<1);
dec(ans,solve(cnt,mxl)%mod);
ckmax(allmxl,mxl);
}
all.resize(all.size()<<1);
add(ans,solve(all,allmxl)%mod);
vis[u]=0;
//printf("rt:%lld\n",u);
}
signed main()
{
n=read();
inv[1]=Finv[0]=F[0]=1;
R(i,2,n+5) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
R(i,1,n+5) F[i]=F[i-1]*i%mod,Finv[i]=Finv[i-1]*inv[i]%mod;
R(i,2,n)
{
static int u,v;
u=read(),v=read();
e[u].pb(v),e[v].pb(u);
}
dfs0(1);
//printf("ans:%lld\n",ans);
ans=(ans%mod+mod)%mod;
writeln(1ll*ans*F[n]%mod);
}
条件概率
令\(P(A\mid B)\)表示在\(B\)事件发生的条件下,\(A\)事件发生的概率,其中\(A,B\)并不是互相独立的。、
然后有
以及贝叶斯公式:
「CTSC2017」游戏
sol
注意到一个位置的决策只和前面第一个已知的结果和后面第一个已知的结果有关,所以考虑已知的结果点分成的一段一段的左闭右开的区间\([i,j)\)。答案其实就是所有区间的贡献加起来。
考虑\(P_{i,j}(x,y)\)表示当第\(i\)局输赢状态为\(x\),第\(j\)局输赢状态为\(y\)的概率,\(E_{i,j}(x,y)\)表示当第\(i\)局输赢状态为\(x\),第\(j\)局输赢状态为\(y\),在此条件下,\([i,j]\)中期望赢的场数。
设\(pro[i][j][k]\)为第\(i-1\)轮输赢状态是\(j\),转到第\(i\)轮输赢状态是\(k\)的概率。考虑如何合并两个区间\([i,pos],[pos+1,j]\)的\(P\)和\(E\)。
首先有:\(P(A\mid B)=\frac{P(AB)}{P(B)}\),然后可以推出:\(E(A\mid B)=\frac{E(AB)}{P(B)}\)。
考虑能合并那就用线段数维护这个东西。对于修改已知的东西的问题,维护一个set,每次修改我们把这个位置的前驱,后继找出来,加一加减一减就行了。
方差相关
矩形覆盖
给定一个大小为\(n\times m\)的矩形,某一些格子上有物品,共有\(k\)个物品,现在等概率选一个子矩形,求子矩形内物品个数的方差。
\(n,m\le 10^9,k\le 10^5\)。
考虑\(Var(X)=E(X^2)-E(X)^2\),分别求\(E(X)\)和\(E(X^2)\)即可。
\(E(X)\)较为好求,即统计每一个点的贡献即可。对于每一个点,统计有多少矩形包含这个点,假设这个点坐标为\((x,y)\),那么就有\(x\times (n-x+1)\times y\times (m-y+1)\)个矩形。
求\(E(X^2)\)可以考虑对于每一对点,统计包含它们的矩形个数,考虑分类讨论它们是左上右下还是右上左下的关系(比如如果是左上右下那么矩形端点就一定在左上点的左上边,右下点的右下边。比如两个点坐标是\((x,y),(z,w)\),那么矩形的个数就是\(x\times (n-w+1)\times z\times (m-y+1)\)),把\(x,y\)本身的贡献算出来,\(z,w\)本身贡献提出来,从左往右扫描线,用数据结构维护\(x\times (m-y+1)\)的和,然后扫到一个点就在数据结构上求一个后缀和即可, 离散化+BIT二维数点即可,实现起来有一些细节,比如同行或同列的情况。
逃跑
还是考虑怎么求\(E(X)\)和\(R(X^2)\)。设\(f(i,j,k)\)表示第\(i\)秒第一次到达\((j,k)\)的概率,根据期望的线性性,答案就是所有\(f(i,j,k)\)的和。设\(g(i,j,k)\)表示第\(i\)秒到达\((j,k)\)的概率,\(g\)可以较为容易的求出。
考虑对于一个点\((x,y)\),设:
那么有
于是\(f\)可以在\(\mathcal O(n^4)\)的时间复杂度内求得。
接着考虑\(E(X^2)\)怎么求,\(E(X^2)=E(2C(X,2))+E(X)\),只要求\(E(C(X,2))\)即可。考虑对于每一对节点算贡献。
设\(h(i,j,k)\)表示第\(i\)秒第一次走到了\((a,b)\),之前已经经过了\((a-j,b-k)\)对于所有不同的\((a,b)\)的概率之和,答案就是所有\(h(i,j,k)\)加起来。考虑\(h\)怎么求。
后面是减去先经过\((a,b)\)再经过\((a-j,b-k)\)的情况。
总时间复杂度\(\mathcal O(n^4)\)。
概率生成函数(PGF)
对于任意取值在非负整数集上的离散随机变量\(X\),它的概率生成函数为:
一些性质
- \(F(1)\)就是求所有项系数之和,概率和一定为\(1\)。
- 期望就是对\(F\)求导之后在\(1\)处的取值。假如次数是\(k\),系数就乘了\(k\),所以求导一下再求和就是期望。
- 同理
- 斯特林展开,展开成下降幂的期望。
[CTSC2006] 歌唱王国
https://www.luogu.com.cn/problem/P4548
设\(A\)为酋长的名字,设\(A\)的长度为\(L\)。令\(a_i\)表示\(A_{1,\ldots ,i}\)是否是\(A\)的一个 border 。设\(f_i\)表示结束时长度是\(i\)的概率,\(g_i\)表示长度为\(i\)时还没有结束的概率。令他们的普通生成函数为\(F(x),G(x)\)。
那么由\(f_i=g_{i-1}-g_i,f_0=0\),得到\(F(x)=xG(x)-G(x)+1\)。
(还有一种理解方法就是\(F+G=xG+1\),表示在没结束的情况下再加上一个数,有可能结束也有可能没有结束,+1表示最初的状态。)
考虑给一个未完成的序列加上\(A\)之后一定已经结束了,但是有可能在未加上\(L\)个字母前就已经结束了,考虑这样的情况填的数一定满足是\(A\)的一个 border ,可以推出\(\left(\frac{x}{m} \right)^L G(x)=\sum\limits_{i=1}^L a_i\left(\frac{x}{m} \right)^{L-i}F(x)\)。
因为结束位置都不一样所以不会算重。
然后对第一个式子求导得到:
然后答案就是
将\(x=1\)代入下面那个式子,得到:
而\(F(1)=1\),所以\(G(1)=\sum_{i=1}^L a_i \cdot m^i\)
Dice
有一个\(m\)面的骰子,求扔连续\(n\)次相同就结束的期望步数和扔连续\(n\)次结果不同就结束的期望步数。
\(n,m\le 10^6\)
同上
对于第一问:
解得:
对于第二问:
解得:
例题
给定一个\(n\)面的骰子,\(n\)是偶数,每次随机扔,有一个计数器,如果扔出是奇数,则计数器清零,如果扔出是偶数,则计数器\(+1\),并且是\(n\)的时候就停止,求停止时计数器的期望值。
还是设\(f_i\)表示计数器为\(i\)时结束的概率,\(g_i\)表示计数器为\(i\)时没有结束的概率,则有:
具体第一个式子是在没有结束的情况下扔一次,就分为两种情况,一种是扔到奇数,一种是扔到偶数。左边就是又可能结束也有可能没有结束,右边就是有\(\frac{1}{2}\)的概率计数器\(+1\),有\(\frac{1}{2}\)的概率计数器变成\(0\)(\(\frac{G(1)}{2}\),\(G(1)\)表示所有情况的和。这里表示不管之前计数器是多少,都有\(\frac{1}{2}\)的概率清零。),\(+1\)是初始情况。
第二个式子表示只要扔到一个\(n\)就结束了。
可以解出
具体先把\(x=1\)代入第二个式子,因为\(F(1)=1\),所以\(G(1)=n\)。然后将\(G(1)=n\)代入第一个式子,再把\(G\)都用\(F\)表示,就可以解出\(F\)。
杂题
Expected Square Beauty
https://codeforces.ml/contest/1187/problem/F
考虑在每段的开头记录贡献,只要它和前面的数不同,它就是某一段的开头。由于要求\(E(X^2)\)所以我们要对每一对数算一下贡献,考虑大部分对的概率都是独立的,可以分开来算,只有两个相同的位置和相邻的位置的贡献不是独立的,考虑相同的位置比较好算,相邻的位置直接容斥即可,即假设相邻的三个位置分别为\(x,x+1,x+2\),贡献则是\(1-P(a[x]=a[x+1])-P(a[x+1]=a[x+2])+P(a[x]=a[x+1]=a[x+2])\)。
English Restaurant
https://codeforces.com/gym/101623/problem/E
考虑将座位按从小到大排序,在最后加入 t 个容量为 inf 的桌子,表示离开。然后最终一定是占用了一些区间的桌子,且每个区间互相独立。考虑先预处理出选到每个区间的概率和期望坐的人数,这个可以直接区间 DP,转移的时候枚举最后被坐的桌子即可。
接着就直接顺序 DP,设\(dp_{i,j}\)表示前\(i\)个桌子,第\(i\)个桌子是某段的结尾,当前共选了\(j\)个桌子的情况,转移时直接前缀和优化即可。
考虑在 DP 时可以维护当前状态的出现概率\(p\),对于当前状态的每一种取值\(x_i\),有\(p_i\)的概率,再维护一个\(e\)表示对于当前状态的所有\(p[i]\cdot x[i]\)的和。这样两个类别\(x,y\)通过加法合并时,结果为\((x.p+y.p,x.e+y.e\)),通过乘法合并时,结果为\((x.p\cdot y.p,x.e\cdot y.p+y.e\cdot x.p)\)。当一个状态\(x\)以\(p\)的概率,权值加上\(y\),转移到其他状态时,直接将被转移的状态加上 \((x.p\cdot p,e\cdot p+y\cdot x.p\cdot p)\) 即可。
时间复杂度 \(\mathcal O((n+t)^3)\)。

浙公网安备 33010602011771号