SAM 略解

· · 个人记录

前言

只要你愿意啃,没有算法是学不来的 ——教练

说实话,学完 SA 后有时间都会去看 SAM ,但就是怀着信息去,带着一脑子问号回来

根据教练の哲理,一定要把 SAM 啃下来

引入

后缀自动机能解决很多问题。

举个例子

当然,这些 SA 也能轻易完成 但是 SAM 能做到很多 SA 做不到的 它最大的优势是在线的 而且它有十分优秀的时间复杂度 O(n)

SAM 的定义

SAM 的基本性质

SAM 保证:

一些例子

可以前往 OI-wiki 查看

一些重要的概念

endpos

定义:我们记 \text{endpos(p)} 表示字符串 p 在原串 s 中所有出现结束位置的集合。 举个栗子,对于 \text{s=ababa}\text{endpos(ab)}=(2,4)\text{endpos(a)}=(1,3,5)

对于两个字串 a , b ,若满足 \text{endpos(a)}=\text{endpos(b)} 我们认为 a,b 是一个等价类。 因此,S 里面所有的字串可以分成若干个等价类。 而我们 SAM 中的节点,就是所有等价类带边的点

一些定理/引理

这个感性证明是最好的,自行理解就行

也是推荐感性理解,长度 x 以下的是当前集合的超集,y 以上的是当前集合的子集 这个区间内一定都是连续的数字,因为字串是连续的 不理解可以看看例子

根据 1.1 可以推证

后缀链接 link

先看张图

S=abcbc

红色的边就是后缀链接

其实用最直白的话来讲 后缀链接就是当前等价类最短后缀的下一个后缀 就是当前等价类的超集 比如说 \text{abcbc} 它的最短后缀是 \text{abc} 那么它连接到的就是 \text{bc} 因为 \text{endpos(bc)}=\{2,4\}

还是很好理解的 手画一下其它节点都满足这个性质

考虑对于任意节点往后缀链接移动,能满足当前等价类的长度不断变短,最终总能到达 t_0 根据 1.3 可以证明不存在环 所有点联通不存在环的无向图就是

对于这棵树 我们称为 \text{parent tree}

即从任意状态往 t_0 走,可以完成遍历完它的所有后缀

我们 SAM 的状态点与 parent tree 的状态是完全相同的

对于一整个字符串 s 它只会在 parent tree 中分裂 |s| 次 所以可以保证节点在最坏条件下是 2n-1

知道这些后,我们可以开始构造 SAM 了

SAM 的构造

SAM 是一个不停往后加字符的在线算法

SAM 是和 parent tree 同时构造的

构造流程 (PS:一定要在纸上边画图边写): 现在我们要加入字符 c

这样就完成了

时间复杂度

是线性的 我们认为是 O(n\log \sum)\sum 是字符集的大小 根据代码 我们知道 SAM 只有 2n-1 个节点 3n-4 条边

构建结束标记

我们只需要在当前最后状态往上跳 link 就能遍历完最大后缀 然后结束标记都是在最后在最后结束的 直接打标记即可