鞅与停时定理小记
赌博问题
设 \(X_i\) 为第 \(i\) 轮赌博后的收益。
根据常识,显然有 \(E(X_i)=X_0=0\)
离散时间鞅
定义一组离散时间鞅为时间离散的随机过程 \(\{X_0,X_1,X_2,...\}\),满足对于任意 \(n\),都有
-
\(|E(X_n)|<+\infty\),即取值是有限的。
-
\(E(X_{n+1}-X_n | X_0,X_1,...,X_n)=0\),意思是确定 \(X_0,X_1,...,X_n\) 后,\(X_{n+1}\) 的期望值等于 \(X_n\)。
停时定理
停时:时间离散的随机过程的终止时刻。
设 \(T\) 为离散时间鞅 \(\{X_0,X_1,...\}\) 的停时。
当满足下面三个条件其中之一时,\(E(X_T)=X_0\) 成立:
-
\(T\) 有界。
-
\(E(|X_{i+1}-X_i|)\) 有界,\(E(T)\) 有限。
-
\(X_i\) 有界。
其中第二个条件是大部分题目都满足的。
势能函数
给出随机过程 \(\{X_0,X_1,X_2,...\}\) 的终止状态 \(X_T\),求 \(E(T)\)。
构造势能函数 \(\varphi(X_i)\),满足:
-
\(E(\varphi(X_{n+1})-\varphi(X_n)=-1|X_0,X_1,...,X_n)=-1\)
-
\(E(\varphi(X_T))\) 为常数,且不存在 \(X'\not = X_T\) 满足 \(\varphi(X')=\varphi(X_T)\)。
设 \(Y_i=\varphi(X_i)+i\),那么容易得到 \(Y\) 是一组离散时间鞅。根据停时定理,\(E(Y_T)=Y_0=\varphi(X_0)\)。
则 \(E(\varphi(X_T)+T)=\varphi(X_0)\Leftrightarrow \varphi(X_T)+E(T)=\varphi(X_0)\Leftrightarrow E(T)=\varphi(X_0)-\varphi(X_T)\)
一般情况下,构造 \(\varphi(X)=\sum\limits_{i\in X} f(i)\)。
例题
CF1025G Company Acquisitions
设接在点 \(u\) 的点个数为 \(c_u\),那么 \(\varphi(X)=\sum\limits_u f(c_u)\)。
若 \(X\to X'\),我们需要满足 \(E(\varphi(X'))-E(\varphi(X))=-1\)。
考虑一次改动选择了两个点 \(u,v\),设 \(x=c_u,y=c_v\),那么
令 \(f(0)=0\)。
直接求即可。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define pir pair<ll,ll>
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
using namespace std;
const ll maxn=510, mod=1e9+7;
ll n,a[maxn],c[maxn],pw[maxn],ans;
int main(){
scanf("%lld",&n);
pw[0]=1;
for(ll i=1;i<=n;i++) pw[i]=pw[i-1]*2%mod;
for(ll i=1;i<=n;i++){
scanf("%lld",a+i);
if(a[i]!=-1) ++c[a[i]];
}
for(ll i=1;i<=n;i++) ans=(ans+1+mod-pw[c[i]])%mod;
ans=(ans+mod-(1-pw[n-1]))%mod;
printf("%lld",ans);
return 0;
}
CF1349D Slime and Biscuits
令 \(m\) 为总饼干数。
设 \(\varphi(X)=\sum\limits_{i=1}^n f(a_i)\)。
那么 \(\sum\limits_{i=1}^n f(a_i)-1=\sum\limits_{i=1}^n (\dfrac {a_i}mf(a_i-1)+\dfrac{(n-2)(m-a_i)}{m(n-1)}f(a_i)+\dfrac{m-a_i}{m(n-1)}f(a_i+1)))\)。三部分分别表示送出饼干、饼干数不变、得到饼干。
考虑对于单个 \(a_i=x\),有
令 \(f(0)=0\),当 \(x=0\) 时得到 \(f(1)=f(0)=0\),直接递推即可。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define pir pair<ll,ll>
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
using namespace std;
const ll maxn=3e5+10, mod=998244353;
ll n,m,a[maxn],f[maxn],ans;
ll power(ll a,ll b=mod-2){
ll s=1;
while(b){
if(b&1) s=s*a%mod;
a=a*a%mod; b>>=1;
} return s;
}
int main(){
scanf("%lld",&n);
for(ll i=1;i<=n;i++) scanf("%lld",a+i), m+=a[i];
ll inv=power(m);
for(ll i=1;i<m;i++)
f[i+1]=m*(n-1)%mod*power(m-i)%mod*(mod-i*inv%mod*f[i-1]%mod+
(mod+1-(n-2)*(m-i)%mod*power(m*(n-1)%mod)%mod)*f[i]%mod+mod-i*inv%mod)%mod;
for(ll i=1;i<=n;i++) ans=(ans+f[a[i]])%mod;
ans=(ans-f[m]+mod)%mod;
printf("%lld",ans);
return 0;
}
CF850F Rainbow Balls
设 \(\varphi(X)=\sum\limits_{i=1}^n f(a_i)\)。
那么
设 \(t=\dfrac{x(m-x)}{m(m-1)}\),得
直接递推时间爆炸,考虑差分。
设 \(g(x)=f(x)-f(x-1)\),那么
那么
令 \(g(0)=m-1,f(0)=0\),得
当 \(x=m\) 时有 \(f(m)=0\),其他只需要递推到 \(10^5\) 即可。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define pir pair<ll,ll>
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
using namespace std;
const ll maxn=3e5+10, mod=1e9+7;
ll n,m,a[maxn],f[maxn],ans;
ll power(ll a,ll b=mod-2){
ll s=1;
while(b){
if(b&1) s=s*a%mod;
a=a*a%mod; b>>=1;
} return s;
}
int main(){
scanf("%lld",&n);
for(ll i=1;i<=n;i++) scanf("%lld",a+i), m+=a[i];
for(ll i=1;i<=1e5;i++)
f[i]=(f[i-1]+power(m-i+1))%mod;
for(ll i=1;i<=1e5;i++)
f[i]=f[i]*(m-1)%mod*(m-i)%mod;
for(ll i=1;i<=n;i++) ans=(ans+f[a[i]])%mod;
printf("%lld",ans);
return 0;
}
CF1479E School Clubs
直接推式子。
令 \(f(1)=-2\),得
考虑对每个 \(f(x)\) 维护分子分母,即 \(f(x)=\dfrac{p(x)}{q(x)}\),分式乘除法即可。
点击查看代码
#include<bits/stdc++.h>
#define ll int
#define pir pair<ll,ll>
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
using namespace std;
const ll maxn=3e5+10, mod=998244353;
ll n,m,a[maxn],p1,q1,p2,q2,ans;
ll power(ll a,ll b=mod-2){
ll s=1;
while(b){
if(b&1) s=1ll*s*a%mod;
a=1ll*a*a%mod; b>>=1;
} return s;
}
int main(){
scanf("%d",&m);
for(ll i=1;i<=m;i++){
scanf("%d",a+i);
n+=a[i];
}
sort(a+1,a+1+m);
p1=-2, p2=0;
q1=q2=1;
ll j=1;
while(j<=m&&a[j]==1) ans-=2, ++j;
for(ll i=1;i<n;i++){
ll p=((long long)(3*n-(i<<1))*p1%mod*q2-(long long)((n<<1)-i)*p2%mod*q1)%mod, q=(long long)(n-i)*q1%mod*q2%mod;
p2=p1, q2=q1;
p1=p, q1=q;
while(j<=m&&a[j]==i+1) ans=(ans+1ll*p*power(q))%mod, ++j;
}
ans=(ans-1ll*p1*power(q1))%mod;
printf("%d",(ans+mod)%mod);
return 0;
}