KMP
KMP 能在线性时间内判断模式串 \(a\) 是否是文本串 \(b\) 的字串。
定义 \(nxt_i\) 表示 \(a\) 中以 \(i\) 结尾的非前缀字串与 \(a\) 的前缀能匹配的最长长度。
如何求出 \(nxt\) 数组:
引理:若 \(x\) 是 \(nxt_i\) 的候选项,那么小于 \(x\) 最大的 \(nxt_i\) 候选项是 \(nxt_x\)。
反证法易证。
所以可以用一个指针 \(j\) 表示当前 \(nxt_{i-1}\) 的候选项,只有此时,\(j+1\) 才是 \(nxt_i\) 的候选项,所以不断尝试 \(j=nxt_j\) 即可。
易得 \(j\) 的减少次数不会超过增加的次数,而且 \(j\) 最多只能增加 \(n\),所以复杂度是线性的。
for(int i=2,j=0;i<=n;i++){
while(j>0&&a[i]!=a[j+1])j=nxt[j];
if(a[i]==a[j+1])j++;
nxt[i]=j;
}
类似可以求出 \(b\) 中以 \(i\) 结尾的字串与 \(a\) 的前缀能匹配的最大长度,如果这个长度为 \(a\) 的长度,则匹配。
P4391 [BOI2009]Radio Transmission 无线传输
模板。
引理: \(s_{[1,i]}\) 具有长度为 \(len\) 的最小循环元,当且仅当 \(len\) 整除 \(i\) 并且 \(i-len\) 是 \(nxt_i\) 的候选项。
P4824 [USACO15FEB]Censoring S
模板。删去后考虑将后一个字符和删去字符串前面的字符进行匹配,将 \(j\) 更新为 \(fail[sta[top]]\) 即可。
用一个栈 \(sta\) 维护当前没有被删掉的串.
P3435 [POI2006]OKR-Periods of Words
由于是最大循环元,所以 \(f[j]\) 表示表示前 \(i\) 个字符的前缀和非前缀后缀的最短匹配。
\(f[i]\) 显然可以通过先求出 \(fail\) 数组,再令 \(j=i\) 后不断递归到 \(fail[j]=0\) 求出。
把求出的 \(f[i]\) 覆盖 \(fail[i]\)。(就是个记忆化)
P3193 [HNOI2008]GT考试
考虑DP。
\(f_{i,j}\) 表示文本串的前 \(i\) 位匹配到模式串的第 \(j\) 位的方案数。
c_{j,k} 表示由 \(k\) 变到 \(j\) 的方案数。
用 KMP 预处理出 \(c\),再跑矩阵加速。

浙公网安备 33010602011771号