KMP

今天对字符串有了一点新的理解,遂再写一篇博客。

字符串取模

定义

可以参考 我之前写的博客。不再赘述。下文用长度表示。

运算

( S + c ) ≡ ( S   m o d   P ) + c ( m o d P ) (S+c) \equiv (S \bmod P) + c \pmod P (S+c)(SmodP)+c(modP)

KMP

定义 g o ( i , c ) go(i, c) go(i,c) 函数,表示 P P P i i i 前缀添加字符 c c c 的字符串的模 P P P 值。定义失配函数(fail) f i f_i fi 表示 P P P i i i 前缀时增加的字符 c c c 失配的模 P P P 值。

g o ( i , c ) = { i + 1 P i = c g o ( f i , c ) P i ≠ c go(i, c) = \begin{cases} i+1 & P_i =c\\ go(f_i,c) & P_i \ne c \end{cases} go(i,c)={i+1go(fi,c)Pi=cPi=c

int go(int i, char c)
{
	if(P[i] == c) return i + 1;
	if(i == 0) return 0;
	return go(f[i], c); 
}

...

f[1] = 0;
for(int i=1; i<P.size(); i++)
	f[i+1] = go(f[i], c); // 这里 

fail 数组分析

关于 f i f_i fi,一方面从自动机角度考虑,即 π i \pi_i πi

一方面从字符串取模的角度考虑, f i = P [ 1.. i ) f_i=P[1..i) fi=P[1..i) P P P 值。 P [ 0.. f i ) P[0..f_i) P[0..fi) P P P 均为本身,根据定义, f i f_i fi 同样满足 π i \pi_i πi 的性质。

复杂度分析

int cur = 0;
for(int i=0; i<text.size(); i++)
{
	cur = go(cur, text[i]);
	...
}

g o go go 函数视为开车, f i f_i fi 视为汽油。cur 表示当前油量。

因为 f i < i f_i < i fi<i,所以开车会消耗汽油, x x x 升汽油最多开车 x x x 公里。每次增加文本字符,开车或者加 1 1 1 升油。显然,加了多少油才能跑多少次,初始为 0 0 0。由此,时间复杂度为线性 。

例题

[模板] KMP

Censoring S


无限猴子类技巧

问题形如出现某个模式串 P P P 的期望长度。

由于只关心匹配,考虑只关心模 P P P 的值,据此结合待定系数法做期望 dp 即可。

例题

无限猴子

[CTSC2006] 歌唱王国


清除模式类技巧

如题,清除字符串中的模式串 P P P

逐位枚举,考虑当前字符串模 P P P 的值即可。

例题

清除模式

Pareidolia G

你可能感兴趣的:(学习笔记,c++)