• 后缀自动机(暂时弃坑)


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


    符号与表达约定

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

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

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


    状态

    显然地, 对于 (subs in Sub_S)(SAM_S(subs) eq 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[ldots 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| ; ig| ; 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) eq 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 eta zeta delta} ; ; stackrel{某种nb方法}{Rightarrow} ; ; SAM_{alpha eta zeta delta Delta})


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

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

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

  • 相关阅读:
    javascript学习笔记-数据类型
    chrome console.log API
    Mysql下SELECT的结果集作为UPDATE的WHERE条件时的SQL语法
    Ajax、Comet、Websocket、SSE
    Model View Controller(MVC) in PHP
    区别Transform、Transition、Animation
    WAI-ARIA无障碍网页应用属性完全展示
    理解 PHP output buffer
    清除Jquery动画的队列
    git常用命令
  • 原文地址:https://www.cnblogs.com/tztqwq/p/13526393.html
Copyright © 2020-2023  润新知