后缀自动机(暂时弃坑)

字符串 \(S\) 的后缀自动机(SAM)是可以接受 \(S\) 的所有后缀的 DFA, 其状态数最少(最简状态自动机)。
\(S\)SAM 的状态数与转移数都是 \(O(|S|)\) 的。


符号与表达约定

1. 对于 \(S = "wowaka"\)\(S[1] = 'w'\)\(S[2] = 'o'\), 意即下标从一开始。

2.\(SAM_S(\text{“string"})\) 表示 \(S\)SAM\(\delta(start, \text{“string")}\) , 意即 \(“string"\) 终止于 \(SAM_S(\text{“string"})\)

3. 分别用 \(Pre_S、Suf_S、Sub_S\) 表示字符串 \(S\) 的 所有前缀组成的集合、所有后缀组成的集合、所有子串组成的集合。


状态

显然地, 对于 \(subs \in Sub_S\)\(SAM_S(subs) \neq NULL\), 然而 \(S\) 的子串数是 \(O(|S|^2)\) 的, 这说明对于不同的 \(subs \in Sub_S\)\(SAM_S(subs)\) 可能相同。
实际上, 对于 \(SAM_S\) 的每个状态, 都有一个唯一的 \(S\)endpos等价类, 使得里面的所有字符串都终止于这个状态。

endpos集合

\(T\) 为一个非空字符串, 则 \(endpos^S(T) = \{r | \exists 1 \le l \le r, S[l\dots r] = T\}\)
特别地, \(endpos^S(NULL) = \{0, 1, \cdots, |S|\}\)[1]

endpos等价类

一个 endpos等价类 就是 \(endpos^S\) 相同的若干 \(S\) 的子串。
\(SAM_S\) 中包含了 \(S\) 的所有 endpos等价类

对于一个状态 \(v\), 用 \(endpos^S(v)\) 表示终止于 \(v\)endpos等价类, 用 \(maxlen(v)\) 表示 \(max\{ |T| \; \big| \; endpos^S(T) = endpos^S(v) \}\)\(minlen(v)\) 类似。

性质 1
任取 \(SAM_S\) 的两个不同状态 \(v_1, v_2\), 则以下三式有且仅有一个成立:
(1) \(endpos^S(v_1) \cap endpos^S(v_1) = \varnothing\)
(2) \(endpos^S(v_1) \subset endpos^S(v_2)\)
(3) \(endpos^S(v_2) \subset endpos^S(v_1)\)

\(Proof.\)
显然啊, 看下 \(endpos^S(v_1) \cap endpos^S(v_1) \neq \varnothing\) 的情况就行了。

性质 2
对于 \(SAM_S\) 的状态 \(v\), 所有满足 \(endpos^S(T) = endpos^S(v)\) 的字符串 \(T\) 的长度会取到 \([minlen(v), maxlen(v)]\) 里的所有整数。

\(Proof.\)
显然, 用 \(A \subseteq S, \; S \subseteq A \; \; \Rightarrow \; \; A = S\) 证就行。


转移

对于状态 \(v\), 其所有出边上的字符 \(c\) 一定是 \(S[r+1], r \in endpos^S(v)\)如果存在的话) , 其所有后继状态 \(nxt\)\(endpos^S(nxt)\) 互不相交。


状态的树形结构

对于两个状态 \(v_1, v_2 \in SAM_S\), 称 \(v_1\)\(v_2\)parent 状态当且仅当 \(endpos^S(v_2) \subset endpos^S(v_1)\)\(|endpos^S(v_1)|\) 最小。[2]

任何状态(除了起始状态)的 parent 状态存在且唯一。

\(Proof.\)
存在性显然。(有 \(endpos^S(NULL)\)
唯一性嘛, 先假设有两个最小的, 由于都真包含一个状态, 所以交起来非空, 然而大小相等, 不可能有真包含的关系, 结合 状态 的性质1, 推出矛盾。

若状态 \(v\)parent 状态为 \(v_1\), 则 \(maxlen(v_1) + 1 = minlen(v)\)

\(Proof.\)
由于 \(endpos^S(v) \subset endpos^S(v_1)\), 所以 \(maxlen(v_1) \in [minlen(v)-1, 0]\), 然而 \(|endpos^S(v_1)|\) 是最小的, 所以 \(maxlen(v_1) = minlen(v)-1\)[3]


状态数

\(SAM_S\) 的状态数是 \(O(|S|)\) 的, 具体地, 不超过 \(2|S| + 1\)

\(Proof.\)
parent 树中, 设 \(f(n)\) 表示 \(|endpos_S| = n\) 的状态的最大子树大小, 显而易见地, \(f(n) \ge 1 + f(x_1) + \cdots + f(x_k) \; \; \; (x_1 + \cdots + x_k = n, \; k \ge 2)\)
然而这并没有什么卵用, 现在用数学归纳法证明 \(f(n) = 2n - 1\)
1. \(n=1, f(n) = 1\), 成立。
2. \(n \ge 2\), 相当于根节点 \(|endpos^S| = n-1\) 的情况下子树根的 \(endpos^S\) 里多了一个元素, 这个元素要么在某路径分叉, 使得整棵树多了一个节点, 要么直到叶子结点, 分两个叉, 使得整棵树多了两个节点, 此时 \(f(n) = f(n-1) + 2 = [2(n-1)-1] + 2 = 2n-1\)


转移数

\(SAM_S\) 的转移数是 \(O(|S|)\) 的, 具体地, 不超过 \(3|S|\)

\(Proof.\)
首先, 以起始节点为根节点求出 \(SAM_S\) 的一颗外向树, 结合状态数上界可知树边数不超过 \(2|S|\)
\(S\) 的每个后缀 \(sf\) 扔到 \(SAM_S\) 上转移, 对于经过的第一条非树边, 让 \(sf\) 与其对应, 每个 \(sf\) 最多对应一条非树边, 这就表明能被后缀对应的非树边最多有 \(|S|\) 条。
显然地, 每个非树边都是某个后缀的对应边(总是可以由起始状态通过树边到达非树边的发起状态), 结合上面的结论, 可知非树边最多有 \(|S|\) 条。


线性构造

采用增量法构造, 即 \(SAM_{\alpha \beta \zeta \delta} \; \; \stackrel{某种nb方法}{\Rightarrow} \; \; SAM_{\alpha \beta \zeta \delta \Delta}\)


  1. 至于为什么多了个 0, 后面会用到。 ↩︎

  2. 这里就用到啦(指[注1]), 显然 \(endpos^S(NULL)\) 真包含任意 \(endpos^S(str), \; str \in Sub_S\)↩︎

  3. 于是要描述后缀自动机的每个节点, 无需存储 \(minlen\), 因为 \(minlen\) 可以由 parent 节点的 \(maxlen+1\) 得到! ↩︎

posted @ 2020-08-19 16:09  xwmwr  阅读(196)  评论(0编辑  收藏  举报