zoukankan      html  css  js  c++  java
  • 后缀自动机【好难不会】

    DAWG, 一种特殊的自动机(Directed Acyclic Word Graph),可以接受一个字符串w的所有子串,而且状态只有O(n)个,其中n是w的长度。

    一个单词的end-set是他在w中出现位置的右端点集合。

    任意两个节点的end-set要么不相交,要么其中一个是另一个的子集。因此可以得到一个树状结构T(w),一个end-set指向他的子集。

    T(w)其实是w的逆序串的后缀树,对于任意一个节点S,假设他的最长子串为x,则x的所有后缀就是S及其所有祖先节点中的字符串集合。

    DAWG可以在线性时间内在线构造。

    其中end-set中包含元素n的状态对应w的后缀,只把这些状态设为接受态,可以得到后缀自动机SAM

    后缀自动机,是一个能识别出原串S所有后缀的自动机。

    简单的想法就是我们对所有的后缀建一棵Trie树,但是长度为n的串,这样的树的空间复杂度就是n^2

    所以要把一些等价的状态合并。

    现在定义一个Right集合,Right(a)表示的是a这个节点表示的子串在原串中出现的右端点(结束位置)。

    那么如果两个节点的Right集合相同,说明其中一个肯定是另一个的后缀,他们怎么拓展都会拓展到同一个节点,所以就合并他们

    并且对于S的任意两个子串,要么没有交集,如果有交集一定是一个包含另一个。并且被包含的那个一定是另一个的后缀。

    比如这是aabbab的后缀自动机

    S表示初始状态,是一个空串。S到任一节点的路径可以构成一个字符串,到任意两个节点构成的字符串不同。

    每个节点有一些值,len,fa,son[]

    len就是这个节点所能表示的字符串的最大长度。而一个节点能表示的字符串就是初始状态S到达他的所有路径表示的字符串。

    son[c]表示的就是从这个节点经过字符c所能到达的节点。

    fa就相当于AC自动机中的fail指针,他表示这个节点的后缀链接。fa是一个节点满足right[fa]包含当前节点的right,并且right[fa]最小的状态。

    我们从初始状态开始,每次如果存在对应的转移就转移,反则沿fa指针回跳,知道存在对应的转移或者跳出了后缀自动机为止。

    后缀自动机构造方法:增量法

    对每个状态s,记他代表的最长子串的长度len[s]

    假设我们当前已经有了前|S|-1个字符的后缀自动机,且现在的自动机中[1,|S|-1]位于状态last,现在加入第|S|个字符,假设他是c,我们新建一个状态np,显然len[np] = |S|

    考虑转移:我们应该加入一个last->np的转移,也应该加入一个fa[last]->np的转移,直到这个状态已经有了一个字符c的转移。设这个状态是p,他经过字符c转移后的状态是q

    那么这时候right[q]就多出一个右端点是|S|的串,且最长长度是len[p]+1

    于是有两种情况

      1.len[q] = len[p] +1,此时q代表的所有串的right任然相同,让fa[np] = q

      2.len[q] > len[p] + 1,这时q代表的串中,长度不超过len[p] + 1的串的right集合会多出一个值|S|。我们就需要新建一个状态nq,nq代表原来q代表的串中所有疮毒不超过len[p] + 1的串,len[nq] = len[p] + 1, 其他属性和原来的q点一致。fa[q] = fa[np] = nq

    然后我们再从p开始,他现在c字符转移到nq,直到发现当前点的c字符转移到的不是q为止。

    后缀自动机的基本性质:

    1.每个状态s代表的串的长度是区间(len[fa[s]], len[s]]

    2.每个状态s代表的所有串在原串中的出现次数及每次出现的右端点相同。

    3.在parent树中,每个状态的right集合是他父状态right集合的子集。

    4.后缀自动机的parent树是原串的反向前缀树。

    5.两个串的最长公共后缀,位于这两个串对应状态在parent树上的最近公共祖先状态。

      一个串对应节点的祖先节点都是他的后缀,深度越大长度越长

    应用:

    1.最长公共子串:

      对其中一个串建立后缀自动机,将另一个串放到后缀自动机上运行,时刻维护当前子串的长度。

    2.字典序k小子串

      对后缀自动机做一遍拓扑,求出从每个点开始可以到达多少个子串。然后从初始状态开始DFS,如果当前状态能到的子串不少于k就继续DFS,否则把k减去当前状态能到的子串个数然后回溯。

    3.字典序最小后缀(最小循环表示)

      把原串复制一遍接到后面,构造后缀自动机。

      从初始状态开始,每次走字典序最小的转移,走|S|次之后得到的就是最小循环表示。

    参考资料:

    2015国家集训队论文71页

    https://github.com/enkerewpo/OI-Public-Library/blob/master/%E5%9B%BD%E5%AE%B6%E9%9B%86%E8%AE%AD%E9%98%9F%E8%AE%BA%E6%96%871999-2017/%E5%9B%BD%E5%AE%B6%E9%9B%86%E8%AE%AD%E9%98%9F2015%E8%AE%BA%E6%96%87%E9%9B%86.pdf

    陈立杰 后缀自动机

    https://github.com/enkerewpo/OI-Public-Library/blob/master/%E5%9B%BD%E5%86%85%E5%AD%A6%E4%B9%A0%E8%B5%84%E6%96%99/2012%E5%B9%B4noi%E5%86%AC%E4%BB%A4%E8%90%A5%E9%99%88%E7%AB%8B%E6%9D%B0%E8%AE%B2%E7%A8%BF(%20%E5%90%8E%E7%BC%80%E8%87%AA%E5%8A%A8%E6%9C%BA%20).ppt

  • 相关阅读:
    vue 前端框架 (二) 表格增加搜索
    vue 前端框架
    数据结构-树的基本操作
    linux的串口驱动分析
    TTY驱动程序架构
    linux MTD系统解析(转)
    DM9000网卡的基本工作原理
    ok6410的LCD裸机范例
    ok6410的DMA裸机总结
    ok6410串口裸机总结
  • 原文地址:https://www.cnblogs.com/wyboooo/p/9908044.html
Copyright © 2011-2022 走看看