概率生成函数([CTSC2006] 歌唱王国 题解)

文章介绍了概率生成函数的概念及其性质,如概率和期望的计算方法,并将其应用于一个字符串随机生成问题中,通过概率生成函数求解字符串长度的期望值。最后给出了一个使用KMP算法的实际编码示例。
摘要由CSDN通过智能技术生成

定义

概率生成函数(Probability Generating Function,PGF,通常情况下以随机变量 X X X 在非负整数集合 N \mathbb{N} N 上为前提),顾名思义,即为概率的生成函数,或者说,如果数列 { p n } \{p_n\} {pn} 满足 P ( X = i ) = p i P(X=i)=p_i P(X=i)=pi(即 { p n } \{p_n \} {pn} X X X 的概率质量函数 PMF 所构成的数列),那么称 { p n } \{p_n\} {pn} 的普通生成函数为 X X X 的概率生成函数:(显然 n ∈ N n\in \mathbb{N} nN

F X ( x ) = ∑ i = 0 + ∞ P ( X = i ) x i F_X(x)=\sum^{+\infty}_{i=0}P(X=i)x^i FX(x)=i=0+P(X=i)xi

其中, P ( X = i ) P(X=i) P(X=i) 表示随机变量 X X X i i i 的概率。

一些性质

  1. 显然 F X ( 1 ) = ∑ i = 0 + ∞ P ( X = i ) = 1 F_X(1)=\sum\limits^{+\infty}_{i=0} P(X=i)=1 FX(1)=i=0+P(X=i)=1(概率之和为 1 1 1);

  2. F X ( x ) F_X(x) FX(x) 求导可以得到 F X ′ ( x ) = ∑ i = 0 + ∞ i P ( X = i ) x i − 1 F_X'(x)=\sum\limits^{+\infty}_{i=0}iP(X=i)x^{i-1} FX(x)=i=0+iP(X=i)xi1,那么此时 F X ′ ( 1 ) = ∑ i = 0 + ∞ i P ( X = i ) = E ( X ) F_X'(1)=\sum\limits^{+\infty}_{i=0} iP(X=i)=E(X) FX(1)=i=0+iP(X=i)=E(X) X X X 的期望为 E ( X ) E(X) E(X));

  3. F X ( x ) F_X(x) FX(x) 求二阶导可得 F X ′ ( x ) = ∑ i = 0 + ∞ i ( i − 1 ) P ( X = i ) x i − 2 F_X'(x)=\sum\limits^{+\infty}_{i=0}i(i-1)P(X=i)x^{i-2} FX(x)=i=0+i(i1)P(X=i)xi2,那么 F X ′ ′ ( 1 ) = ∑ i = 0 + ∞ i 2 P ( X = i ) − ∑ i = 0 + ∞ i P ( X = i ) = E ( X 2 ) − E ( X ) F_X''(1)=\sum\limits^{+\infty}_{i=0} i^2P(X=i)-\sum\limits^{+\infty}_{i=0} iP(X=i)=E(X^2)-E(X) FX′′(1)=i=0+i2P(X=i)i=0+iP(X=i)=E(X2)E(X) ,所以 E ( X 2 ) = F X ′ ′ ( 1 ) + E ( X ) = F X ′ ′ ( 1 ) + F X ′ ( 1 ) E(X^2)=F_X''(1)+E(X)=F_X''(1)+F_X'(1) E(X2)=FX′′(1)+E(X)=FX′′(1)+FX(1),可得 D ( X ) = E ( X 2 ) − ( E ( X ) ) 2 = F X ′ ′ ( 1 ) + F X ′ ( 1 ) ( 1 − F X ′ ( 1 ) ) D(X)=E(X^2)-(E(X))^2=F_X''(1)+F_X'(1)(1-F_X'(1)) D(X)=E(X2)(E(X))2=FX′′(1)+FX(1)(1FX(1)) X X X 的方差为 D ( X ) D(X) D(X));

这些性质可以用来简化一些推导 QwQ。

P4548 [CTSC2006] 歌唱王国(芝士一道可用概率生成函数推导的字符串奇妙题目)

题意简述

字符集大小为 n n n,处理 t t t 组数据,每组数据给出一个长度为 m m m 的字符集 S S S,空串 T T T 每次随机加入一个字符,直到 T T T 中出现 S S S 停止,求 T T T 停止时长度的期望。

做法

显然不能直接硬算,先设变量 Y Y Y 表示停止时 T T T 的长度,再引入两个概率生成函数 f ( x ) f(x) f(x) g ( x ) g(x) g(x) 分别表示 Y = i Y=i Y=i 的概率和 Y > i Y>i Y>i 的概率,即 f ( x ) = ∑ i = 0 + ∞ P ( Y = i ) x i f(x)=\sum^{+\infty}_{i=0}P(Y=i)x^i f(x)=i=0+P(Y=i)xi g ( x ) = ∑ i = 0 + ∞ P ( Y > i ) x i g(x)=\sum^{+\infty}_{i=0}P(Y>i)x^i g(x)=i=0+P(Y>i)xi,为了方便我们分别用 f i f_i fi g i g_i gi 表示 f f f g g g i i i 次项的系数,那么 f i f_i fi 就表示在第 i i i 次添加停止的概率, g i g_i gi 就表示在第 i i i 次添加仍未停止的概率,最终我们要求的期望 E ( Y ) = f ′ ( 1 ) E(Y)=f'(1) E(Y)=f(1),接下来的任务便是找式子求期望了。

第一个式子——转化期望

首先我们可以根据 f f f g g g 的定义来确定一个递推式,因为 Y Y Y 一定是一个正整数,所以 Y > i Y>i Y>i 等价于 Y ≥ i + 1 Y\ge i+1 Yi+1,手动分类讨论一下(等于和大于的情况)可得 g i = f i + 1 + g i + 1 g_i=f_{i+1}+g_{i+1} gi=fi+1+gi+1,整理成生成函数得到 x g ( x ) + 1 = f ( x ) + g ( x ) xg(x)+1=f(x)+g(x) xg(x)+1=f(x)+g(x) + 1 +1 +1 是补上 g 0 = 1 g_0=1 g0=1 的项),由于我们要求 f ′ ( 1 ) f'(1) f(1),那么就可以用 g g g 来表示 f f f,即

f ( x ) = ( x − 1 ) g ( x ) + 1 f(x)=(x-1)g(x)+1 f(x)=(x1)g(x)+1

求个导可得 f ′ ( x ) = g ( x ) + ( x − 1 ) g ′ ( x ) f'(x)=g(x)+(x-1)g'(x) f(x)=g(x)+(x1)g(x),最终我们有 f ′ ( 1 ) = g ( 1 ) f'(1)=g(1) f(1)=g(1),皆大欢喜 🎉,这意味着只要我们能求出 g ( 1 ) g(1) g(1) 就能得到答案了。

第二个式子——求 g ( 1 ) g(1) g(1)

接下来我们又设一个数列 h i h_i hi 表示在第 i i i 次操作后仍未结束,强制性地给 T T T 随机加上长度为 m m m 的串 S S S 的概率(强制表示可能有尚未加满 m m m 个字符就已经出现了 S S S 的情况,但仍然继续加字符直到加满了 m m m 个字符,并且根据定义,加入的 m m m 个字符能组成串 S S S),那么就相当于我们在 g i g_i gi 的情况下强制加了 m m m 个字符,于是能得到 h i = g i × n − m h_i=g_i\times n^{-m} hi=gi×nm

但同时我们能发现此时能够满足 h i h_i hi 条件的 Y Y Y 应该有 i < Y ≤ i + m i<Y\le i+m i<Yi+m,对于 Y Y Y 的每一种值我们可以单独讨论,假设 Y = y Y=y Y=y t = y − i t=y-i t=yi 0 < t ≤ m 0<t\le m 0<tm),前提概率便是 f y f_y fy,我们只需求再补上串 S S S 的长为 m − t m-t mt 的后缀使得加入这 m − t m-t mt 个字符后最后 m m m 个字符能形成串 S S S f y × n t − m f_y\times n^{t-m} fy×ntm 之和就能得到 h i h_i hi,由于在第 y y y 次加入时已经满足出现长度为 m m m 的子串 S S S,那么显然第 i + 1 ∼ y i+1\sim y i+1y 次加入的字符构成的串同时为串 S S S 的前、后缀,换种说法即为 t t t 属于串 S S S 的 Border 或者 t = m t=m t=m(这么说是因为 Border 的定义要求字符串本身不为该字符串的 Border),形式化地: h i = ∑ t = 1 m p d ( t ) f y × n t − m h_i=\sum\limits^m_{t=1} pd(t)f_y\times n^{t-m} hi=t=1mpd(t)fy×ntm,其中 p d ( t ) pd(t) pd(t) 取值为 0 0 0 1 1 1,表示判断 t t t 是否满足 t = m t=m t=m t t t S S S 的 Border 的条件。

结合这两种 h i h_i hi 的求法,可得到 g i × n − m = ∑ t = 1 m p d ( t ) f y × n t − m = n − m × ( ∑ t = 1 m p d ( t ) f y × n t ) g_i\times n^{-m}=\sum\limits^m_{t=1} pd(t)f_y\times n^{t-m}=n^{-m}\times\big(\sum\limits^m_{t=1} pd(t)f_y\times n^t\big) gi×nm=t=1mpd(t)fy×ntm=nm×(t=1mpd(t)fy×nt),又知道 y = i + t y=i+t y=i+t,于是 g i = ∑ t = 1 m p d ( t ) f i + t × n t g_i=\sum\limits^m_{t=1} pd(t)f_{i+t}\times n^t gi=t=1mpd(t)fi+t×nt,转化为生成函数形式:

x m g ( x ) = ∑ t = 1 m x m − t f ( x ) p d ( t ) × n t x^{m}g(x)=\sum^m_{t=1}x^{m-t}f(x)pd(t)\times n^t xmg(x)=t=1mxmtf(x)pd(t)×nt

代入可得 g ( 1 ) = ∑ t = 1 m f ( 1 ) p d ( t ) × n t = ∑ t = 1 m p d ( t ) × n t g(1)=\sum\limits^m_{t=1}f(1)pd(t)\times n^t=\sum\limits^m_{t=1}pd(t)\times n^t g(1)=t=1mf(1)pd(t)×nt=t=1mpd(t)×nt,综上,最终的答案便为 ∑ t = 1 m p d ( t ) × n t \sum\limits^m_{t=1}pd(t)\times n^t t=1mpd(t)×nt,直接上 KMP 就做完啦,完结撒花✿✿ヽ(°▽°)ノ✿。

上代码

#include <bits/stdc++.h>
#define mod 10000
#define File(xxx) freopen(xxx".in","r",stdin),freopen(xxx".out","w",stdout)
using namespace std;
typedef long long LL;
const int N = 1e5+5;
int k, t, n, nxt[N], a[N], vis[N], pw[N], ans;

template <typename T> inline void debug(T x) { cerr<<x<<'\n'; }
template <typename T, typename ...T_> inline void debug(T x, T_ ...p) { cerr<<x<<' ', debug(p...); }
template <typename T> void read(T& x) {
	x = 0; int f = 0; char c = getchar();
	while(c < '0' || c > '9') f |= (c == '-'), c=getchar();
	while(c >= '0' && c <= '9') x=(x<<1)+(x<<3)+(c^48), c=getchar();
	x=(f ? -x : x);
}
int lne; char put[105];
template <typename T> void write(T x, char ch) {
	lne = 0; if(x < 0) putchar('-'), x=-x;
	do { put[++lne]=x%10, x/=10; } while(x);
	while(lne) putchar(put[lne--]^48);
	putchar(ch);
}
int upd(int x) {
	return (x >= mod ? x-mod : x);
}

signed main() {
	read(k), read(t);
	pw[0]=1;
	for(int i = 1; i <= 100000; ++i)
		pw[i]=1LL*pw[i-1]*k%mod;
	while(t--) {
		read(n);
		ans=0;
		for(int i = 1; i <= n; ++i)
			read(a[i]), vis[i]=0;
		for(int i = 2, j = 0; i <= n; ++i) {
			while(j && a[j+1] != a[i]) j=nxt[j];
			if(a[j+1] == a[i]) ++j;
			nxt[i]=j;
		}
		int now = n;
		while(now) 
			ans=upd(ans+pw[now]), now=nxt[now];
		if(ans < 1000) putchar('0');
		if(ans < 100) putchar('0');
		if(ans < 10) putchar('0');
		write(ans, '\n');
	}
	return 0;
}
  • 47
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值