鞅的停时定理

看来还得再推迟一点。今天是鞅的停时定理。

在此之前先挂个假人:

我:今天T3算不算科技人被科技打败了)

某人:
大概吧(

但我也不算科技人啊

我是个废物 科技打败了废物

科技揍扁了废物

名字就不透露了,防止被 d。啊好像已经被 d 了。后续可以去他那里找。

总之今天 T3 大概算是科技人被科技打败了。但是科技人不死于徒手所以来补一下这个点。(某种程度上这个也算是我曾经看过但是看不懂所以弃了的东西之一)

然后发现一个问题,就是鞅的停时定理这东西关键不在定理,在势能函数。也就是说你就算不知道这是个什么东西也能构造函数求解。

离散时间鞅

开始抄定义。

这是一个时间离散的随机过程 \(\{X_0,X_1,X_2,\cdots\}\),使得对于 \(\forall n\in \mathbb{N}\) 满足:

  1. \(E(|X_n|)<\infty\)
  2. \(E(X_{n+1}-X_n|X_0,X_1,\cdots,X_n)=0\)
    第二个就是条件期望,在已知 \(X_0-X_n\) 的情况下有 \(E(X_{n+1}-X_n)=0\)。那么容易推出来 \(E(X_n)=X_0\)

停时

停时:关于随机过程 \(\{X_0,X_1,\cdots\}\) 的停时是一个非负随机变量 \(T\) (可以为 \(\infty\)),满足对于任意 \(n\)\([n=T]\) 的取值仅与 \(X_0,X_1,\cdots,X_n\) 有关。

带停时的随机过程:对于随机过程 \(\{X_0,X_1,\cdots\}\) 的停时为 \(T\) ,则其带停时的随机过程 \(\{Y_0,Y_1,\cdots\}\) 为:

\[Y_n=\begin{cases}X_n,\quad n\le T\\X_T,\quad n>T\end{cases} \]

就是在停时之后不变。

鞅的停时定理

设鞅 \(\{X_0,X_1,\cdots\}\) 的停时为 \(T\) ,当下列三个条件之一成立时,有 \(E(X_T)=X_0\)

  1. \(T\) 几乎必然有界(即存在常数 \(k\) 满足 \(P(T\le k)=1\));
  2. \(|X_{i+1}-X_i|\) 一致有界,\(E(T)\) 有限(即存在常数 \(k\) 满足 \(P(E(|X_{i+1}-X_i)\le k)=1\));
  3. \(Y_i\)\(X_i\) 的带停时的随机过程)几乎必然有界。

看起来好乱。不过用法和上边那个东西似乎关系不是很大。

这玩意的一般用法是构造势能函数 \(\phi(A)\) 满足 \(E(\phi(A_{n+1})-\phi(A_n)|A_0,A_1,\cdots,A_n)=-1\)\(\phi(A_n)\) 为常数,那么随机事件 \(\{X_0,X_1,\cdots\}\) 满足 \(X_n=\phi(A_n)+n\) 即是鞅。根据停时定理,\(E(X_n)=E(X_0)\),也就是说

\[E(n)=\phi(A_0)-\phi(A_n) \]

感性理解一下就是每次操作一步势能就 \(-1\),那么初势能 \(-\) 末势能就是期望步数。

用到这个东西的题好像都是让你求一个事件的期望终止时间。这时候就把答案当做停时然后构造势能函数。举几个例子。

CF1349D Slime and Biscuits

题意:有 \(n\) 个人,第 \(i\) 个有 \(a_i\) 个饼干,每次随机选一个饼干随机给剩下 \(n-1\) 个人中的一个,当一个人有所有饼干时停止,求期望步数。

以下设 \(m=\sum a_i\)

仍然构造势能函数 \(\phi(A_T)=\sum_{i=1}^nf(a_i)\) ,其中 \(a_i\)\(T\) 步后第 \(i\) 个人的饼干数。

那么我们要让 \(E(A_{n+1}-A_n|A_0,A_1,\cdots,A_n)=-1\)。一步内势能减少 \(1\),那么我们只需要找到执行一步前的势能和执行一步后的势能。如果执行一步前的势能是 \(\sum_{i=1}^nf(a_i)\),那么枚举选中了谁的饼干和分给哪个人,有:

\[\sum_{i=1}^nf(a_i)-1=\sum_{i=1}^n\frac{a_i}m\left(f(a_i-1)+\sum_{j\neq i}\frac 1{n-1}f(a_j+1)+\frac{n-2}{n-1}f(a_j)\right) \]

每个人有 \(\frac{a_i}m\) 的概率被选中拿出饼干,然后枚举剩下的人,每个人有 \(\frac 1{n-1}\) 概率拿到饼干,剩下的概率拿不到饼干。全都加起来就行了。

然后开始化右边的式子。

\[\begin{aligned} &\sum_{i=1}^n\frac{a_i}m\left(f(a_i-1)+\sum_{j\neq i}\frac 1{n-1}f(a_j+1)+\frac{n-2}{n-1}f(a_j)\right)\\ =&\sum_{i=1}^n\frac{a_i}mf(a_i-1)+\frac {a_i}m\sum_{j\neq i}\frac 1{n-1}f(a_j+1)+\frac{n-2}{n-1}f(a_j)\\ =&\sum_{i=1}^n\frac{a_i}mf(a_i-1)+\frac {m-a_i}{m(n-1)}f(a_i+1)+\frac{(m-a_i)(n-2)}{m(n-1)}f(a_i) \end{aligned} \]

单独考虑一项:

\[f(x)-\frac xm=\frac xmf(x-1)+\frac{m-x}{m(n-1)}f(x+1)+\frac{(m-x)(n-2)}{m(n-1)}f(x) \]

于是可以递推 \(f\) 了。将 \(x=0\) 代入得到 \(f(0)=f(1)\),所以这俩取什么数并不影响答案。为了方便我们可以取 \(0\)(如果不信可以试一下,反正我初始化 \(114514\) 是没有问题的)。

最后用初势能减去末势能就可以了。

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int mod=998244353;
int n,m,ans,a[5000010],b[5000010],f[10000010],inv[10000010];
int main(){
	scanf("%d",&n);inv[1]=1;
	for(int i=1;i<=n;i++)scanf("%d",&a[i]),m+=a[i];
	for(int i=2;i<=max(n,m);i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
	for(int i=1;i<m;i++){
		f[i+1]=(1ll*(1-1ll*(m-i)*(n-2)%mod*inv[m]%mod*inv[n-1]%mod+mod)%mod*f[i]%mod-1ll*i*inv[m]%mod*(f[i-1]+1)%mod+mod)%mod;
		f[i+1]=1ll*f[i+1]*m%mod*(n-1)%mod*inv[m-i]%mod;
	}
	for(int i=1;i<=n;i++)ans=(ans+f[a[i]])%mod;
	printf("%d\n",(ans-f[m]+mod)%mod);
	return 0;
}

CF1025G Company Acquisitions

这个题还好,比上边那个顺手不少。

套路设 \(f(x)\) 为有 \(x\) 个儿子的势能,那么 \(n\) 步的势能 \(\phi(n)\) 就是所有被选中的节点的势能之和。

考虑一次操作前后的势能。假设两个分别有 \(x,y\) 个儿子的节点被选中,那么易得

\[f(x)+f(y)-1=\frac {f(x+1)+yf(0)+f(y+1)+xf(0)}2 \]

为得到递推式,代入 \(y=x\),得到

\[2f(x)-1=f(x+1)+xf(0) \]

\(f(0)\) 仍然不影响,所以为方便可以设为 \(0\) ,那么得到通项 \(f(x)=1-2^x\)。算就完了。

(所以为啥这题 \(n\le 500\)

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int mod=1000000007;
int n,ans,cnt[510];
bool v[510];
int qpow(int a,int b){
	int ans=1;
	while(b){
		if(b&1)ans=1ll*ans*a%mod;
		a=1ll*a*a%mod;
		b>>=1;
	}
	return ans;
}
int f(int x){
	return (1-qpow(2,x)+mod)%mod;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int x;scanf("%d",&x);
		if(~x)cnt[x]++;
		else v[i]=true;
	}
	for(int i=1;i<=n;i++){
		if(v[i])ans=(ans+f(cnt[i]))%mod;
	}
	ans=(ans-f(n-1)+mod)%mod;
	printf("%d\n",ans);
}

CF850F Rainbow Balls

这玩意 tm 推一半给我整出公式恐惧症来了。今天的数学就先到这里。

仍然套路设 \(f(a_i)\) 是操作 \(n\) 次之后颜色 \(i\) 的势能。套路找操作后的势能:

\[\sum_{i=1}^nf(a_i)-1=\sum_{i=1}^n\frac{a_i}m\left(\sum_{j\neq i}\frac{a_j}{m-1}\left(f(a_i+1)+f(a_j-1)+\sum_{k\neq i,k\neq j}f(a_k)\right)\frac{a_i-1}{m-1}\sum_{j=1}^nf(a_j)\right) \]

进行一大堆粗糙的体力活之后可以得到通项(这段我实在不想写了球球了放过我吧):

\[f(x+1)=2f(x)-f(x-1)-\frac{m-1}{m-x} \]

然而这 \(O(\sum a_i)\) 的复杂度看上去就很不靠谱。实际上也确实很不靠谱。所以继续整一点很神奇的转化。

差分一下,设 \(g(x)=f(x)-f(x-1)\),那么

\[g(x+1)=g(x)-\frac{m-1}{m-x}\\ g(x)=g(0)-\sum_{i=0}^{x-1}\frac{m-1}{m-i}\\ \begin{aligned} f(x)&=f(0)+\sum_{i=1}^xg(i)\\ &=f(0)+xg(0)-\sum_{i=1}^n\sum_{j=0}^{i-1}\frac{m-1}{m-j}\\ &=f(0)+xg(0)-(m-1)\sum_{j=0}^{x-1}\frac{x-j}{m-j}\\ &=f(0)+xg(0)-(m-1)\sum_{j=0}^{x-1}\frac{x-m}{m-j}-1\\ &=f(0)+xg(0)-(m-1)(x-m)\sum_{j=0}^{x-1}\frac 1{m-j}-x(m-1) \end{aligned} \]

接下来就是找个合适的初值方便算数。主要的麻烦是算 \(f(m)\)。代一下发现 \(f(m)=f(0)+mg(0)-m(m-1)\)。如果取 \(f(0)=0,g(0)=m-1\),那么 \(f(m)=0\)。剩下的可以递推。

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int mod=1000000007;
int n,m,ans,a[2510],f[100010];
int qpow(int a,int b){
	int ans=1;
	while(b){
		if(b&1)ans=1ll*ans*a%mod;
		a=1ll*a*a%mod;
		b>>=1;
	}
	return ans;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]),m+=a[i];
	f[0]=0;f[1]=1ll*(m-1)*(m-1)%mod*qpow(m,mod-2)%mod;
	for(int i=1;i<100000;i++)f[i+1]=(2ll*f[i]-f[i-1]-1ll*(m-1)*qpow(m-i,mod-2)%mod+mod+mod)%mod;
	for(int i=1;i<=n;i++)ans=(ans+f[a[i]])%mod;
	printf("%d\n",ans);
	return 0;
}
posted @ 2023-01-31 21:36  gtm1514  阅读(137)  评论(0编辑  收藏  举报