KMP 自动机
KMP 自动机
有时候我们需要重复跳KMP上的nxt[],每次都跳太劣了,我们考虑优化它。
显然,我们都知道,每个nxt[i],都有nxt[i]<i,我们将所有nxt[i]->i连边,我们会发现它们构成一棵树,这被叫做失配树。
我们每次跳nxt[]的过程都相当于在树上跳祖先,我们发现很多过程在树上都变得显然了。
比如我们要在另一个字符串上匹配一个串,我们找到最长的匹配长度,就相当于跳祖先和跳到另一个串。
我们发现这个转移构成一张图,在图上找点就做完了。
我们发现跳祖先太慢了,多次操作可能会T。
例题 Prefix Function Queries
题意简述:每次在\(S\)串后加几个字符,求新加进来的字符的nxt[],询问间独立。
数据范围:\(|S|\le 10^6,q\le 10^5,|T|\le 10\)
我们暴力跳,时间复杂度是\(O(|S|+|S||T|q)\),显然不能过。
我们发现跳nxt[]是个非常单调的过程,我们每次都在往前跳直到\(s[j+1]=s[i]\)。
我们发现这个东西的数量很小,只有\(O(1e6\times 26)\),不妨将它离线下来:
我们定义\(T(i,j)\)从\(i\)开始,往前跳nxt[],直到\(nxt[i]=j\)为止,我们最后在的位置。
本质上就是\(i\)匹配字符\(j\)的位置。
有:
我们要将前\(n\)个和后\(m\)个接起来。
所以我们要强制让第\(n+1\)和\(n\)接起来,让它从\(n\)开始跳。
所以有:
然后这道题就做完了,但是我们对算法的探索永无止境。
前面我们提到所有的nxt[]构成一颗失配树,我们将每个点拆成\(O(26)\)个状态。
我们发现,在原有的失配树上,有一些其他的边,从一个点指向它的祖先中的一点,容易发现,我们打破的原来的树性质,加入了一些压缩后的路径,它构成一个DAG。
我们在压缩后的路径上跳是\(O(1)\)的,这就是KMP 自动机。

浙公网安备 33010602011771号