后缀自动机 SAM
0.前言
这种东西不知道是怎么发明出来了的。感觉很 nb。
但是应该比 KMP 简单些吧。
1.概念
SAM,即后缀自动机,是对于一个字符串 \(s\) 来说能够表示其所有子串/后缀的 DFA。实际上 SAM 是一个 DAG,上面有若干点代表若干状态,其中有一个初始状态 \(t_0\),这些状态所代表的字符串可能不止一个,SAM 上的边代表若干转移,每个转移是一个字母,从一个状态连接到另一个状态。SAM 上的每条从 \(t_0\) 作为起始点的路径上的所有转移所组成的字符串实际上是原字符串 \(s\) 的某个子串,这个子串属于这条路径的终点的状态所代表的字符串集合。
2.神秘性质
right 集合
首先我们定义:对于字符串 \(s\) 的一个非空子串 \(s_0\),其 right 集合为 \(s_0\) 在 \(s\) 中出现的所有结束位置。
显然,可以得到如下性质:
-
SAM 上的一个状态对应着若干 right 集合相同的子串,如果将这些子串按长度从小到大排序之后,它们的长度连续。
-
\( \begin{cases} right(x) \subseteq right(y) & \text{if y is a suffix of x.}\\ right(x) \cap right(y) = \phi & \text{otherwise.} \end{cases} \)
-
如果子串 \(x\) 与 \(y\) 的 right 集合相同,那么较短的那个一定是较长的后缀。
后缀链接 fa
根据 right 集合的性质,我们可以根据 SAM 的 DAG 构建 Parent Tree。
对于状态 \(X\),其后缀链接就是连接到 right 集合不同的最长后缀所属状态 \(Y\) 上。
令 \(t\) 为状态 \(X\) 中最长的字符串,现在我们知道字符串 \(t\) 的前若干个后缀的 right 集合与 \(t\) 相同,而后若干个后缀的 right 集合不与 \(t\) 相同,令满足后者的最长后缀为 \(v\),则 \(right(t) \subseteq right(v)\)。
这就相当于不断地在 \(t\) 的开头删除字母,所得到的字符串长度会越来越短,当删到某一个后缀 \(v\) 时,发现其不仅在 \(t\) 出现的这些地方出现过,还在原串 \(s\) 的其他地方出现过。所以其 right 集合会变大,且包含 \(right(t)\) 中的元素。
那么 \(X\) 的后缀链接会连接到 \(v\) 所在状态 \(Y\) 上。
-
所有的后缀链接会构成一棵以 \(t_0\) 为根节点的树。
-
通过 right 集合构造的树(每个子节点的 right 集合都包含在父节点的 right 集合中)与通过后缀链接构造的树相同。
-
在维护 SAM 的时候,通常会记录状态所代表子串的最大长度 \(len_u\),可以发现,在 Parent Tree 上,一个状态代表子串的长度范围应为 \([len_{fa_u} + 1,len_u]\)。
上述性质是显然的。我们建出来的自动机实际上是 DAG + Parent Tree。
3.构造 SAM
令一个状态 \(u\) 代表子串中最长子串为 \(longest(u)\)。
当前字符串为 \(s\),新加入的字符为 \(c\),新添加的状态为 \(u\)。构造过程如下:
从上一次 \(s\) 的状态 \(p\) 开始向上跳后缀链接,直到 \(p\) 在 DAG 上有一条为 \(c\) 的转移;
如果没有找到,那么我们添加的就是一个新字母,\(fa_u = t_0\) 即可。如果找到了,令这个转移到的状态为 \(q\):
- 如果 \(len_q = len_p + 1\),证明 \(q\) 只代表 \(longest(p) + c\) 这一个子串,直接将 \(u\) 的后缀链接到 \(q\);
- 如果 \(len_q > len_p + 1\),证明 \(q\) 不止代表 \(longest(p) + c\) 这一个子串,这时我们需要将 \(q\) 拆开,拆为一个只代表 \(longest(p) + c\) 这一个子串的状态 \(now\) 和剩余部分 \(q'\),将 \(now\) 的后缀链接连接到 \(p\),并将 \(q'\) 与 \(u\) 的后缀链接连接到 \(now\),接着,我们继续用 \(p\) 通过后缀链接向上跳,如果存在状态有为 \(c\) 的转移是指向原本的 \(q\) 的,将其指向 \(now\)。
这么做是因为我们从 \(s\) 所属状态开始跳后缀链接,而达到的点均为 \(s\) 的后缀,当这些后缀中存在为 \(c\) 的转移时,这个转移所到达的状态一定是 \(s + c\) 的一个后缀且是最长的 right 集合与 \(right(u)\) 不同的后缀。
SAM 便构造完毕。
4.不错的应用
oi-wiki 已经足够详细。

浙公网安备 33010602011771号