Loading

普及 SAM

参考了一些博客,如有侵权,请告知。

内部资料,包不外传。

定义

后缀自动机(SAM)的结构包含两部分,有向无环单词图(DAWG)和 parent 树。SAM 中的每个节点都同时存在于这两个结构中。

以下假设我们是关于字符串 \(s\) 的 SAM。

DAWG

DAWG 是一个 DAG。

我们令起始结点为 \(st\)\(st\) 在 DAWG 中表示一个空串,而其他所有结点均 \(s\) 的一个或多个子串。

对于 DAWG 中的每条有向边都有一个字符 \(c\),一个结点 \(x\) 所包含的子串为从 \(st\) 走到 \(x\) 路径上的字符依次拼接得到的结果,因为有多条路径,所以结点 \(x\) 可能包含很多子串。

为了描述方便,如果结点 \(x\) 包含 \(s\) 的一个后缀,那么我们称这个点为关键点。

结点

  • 每一个结点代表的所有子串,一定是 \(s\) 某个前缀中若干长度只相差 \(1\) 的后缀。
  • 结点 \(x\) 代表的所有子串中,最长子串长度记为 \(\max ( x )\),最短子串长度记为 \(\min ( x )\)
  • 我们记 endpos 为一个子串在 \(s\) 中所有出现过的结尾位置集合,则一个结点所有子串的 endpos 相同。
  • 任意两个结点的 endpos 不同,否则即可将其合并为一个结点。

有向边

\(u \to v\) 有连边则表示 \(u\) 的所有子串加上这条边所代表的字符 \(c\) 后能够变成的子串被 \(v\) 包含,但不一定其是 \(v\) 的所有子串(\(v\) 可能由多个点连边转移过来)。

后缀链接与 parent tree

注意:后缀链接并没有和 DAWG 中的有向边有直接联系。

  • \(u\) 的后缀链接所指的结点为 \(nxt_u\),如果 \(nxt_u = v\),当且仅当 \(\min(u) = \max (v) + 1\),且 \(nxt_u\) 的子串是 \(u\) 的子串的后缀。
  • 对于 \(u\)\(nxt_u\) 来说,\(nxt_u\) 的 endpos 集合包含 \(u\) 的 endpos 集合。
  • 后缀链接本质构成了一棵以 \(st\) 为根的内向树,我们称这棵树为 parent tree。

构造

大家可以通过构造感受 SAM 的有向边和后缀链接所表示的深层含义。

正常情况下,构造 SAM 的复杂度是 \(O(nV)\) 的,\(V\) 为字符集大小。

SAM 的构造是一个在线的增量算法,也就是说我们通过 \(s\) 的 SAM 得出 \(s + c\) 的 SAM。一般情况下我们选择直接记代码,当然你也可以通过下述例子感受 SAM 的构造过程与严谨逻辑。

首先,当 \(s\)acbabc 时,我们的后缀自动机应该长这样(比较复杂,其实是为了让读者更清楚的理解 SAM 的结构,注意看清楚箭头方向):

解释一下其中的东西:

  • 虚线表示有向边,实边表示后缀链接,\(u \to nxt_u\) 有一条有向的实边(后缀链接)。
  • \(v_1\)\(st\) 结点,也就是起始结点,其中 \(v_2, v_3, v_4, v_5, v_6, v_7\) 代表子串之一是 \(s\) 的一个后缀,其中 \(v_7\)\(s\) 串,然后从 \(v_6\)\(v_2\) 长度递减,这些点也就是我们上面说过的关键点。
  • 为了方便,我们将把 \(v_2, v_3, ..., v_9\) 这些结点所代表的字符串表示出来,如果你不记得表示哪些字符串了,可以看一眼。
    • \(v_2\)
posted @ 2024-11-08 08:16  Alexande  阅读(44)  评论(0)    收藏  举报