[SAM]后缀自动机

定义

一个串S的后缀自动机是一个有限状态自动机,它能且只能接受所有S的后缀,并且拥有最少的状态和转移

构造

几个定义

定义后缀自动机的母串为S,令S[l, r]表示S中第l个字符到第r个字符组成的子串,令从第i个位置开始的后缀为 sufi ,到第i个位置结束的前缀为 prei
SAMstr 表示从初始状态读入字符串str之后的状态
对于一个S的一个子串str,令 rightstr 表示str在S中每一次出现的右端点位置组成的集合

复杂度证明

状态数线性
考虑一个串str,若str是S的一个子串,那么 SAMstr 应该是一个合法状态,因为我们可以在str后添加若干字符来变成S的一个后缀,这个后缀应该被自动机接受,否则如果str不是S的子串,那么 SAMstr 应该是一个不合法的状态,因为无论怎样添加字符它也不会变成S的一个后缀
也就是说,对于S的每一个子串str,都应该在SAM中找到对应的状态,这样来看,SAM的状态应该是 O(n2)
这时候,我们考虑一个子串str,如果 rightstr righta+str 完全一致,我们就可以把它们合并成同一个状态,因为我们从这两个后缀开始添加字符,得到的后缀是一样的,因此这两个串在SAM中本质相同,可以合并为一个结点
我们继续考虑S的两个子串A和B,如果 rightA rightB 有交,那么一个串必然是另一个串的后缀,也就意味着对于S任意两个子串,它们的 right 集合要么没有交集,要么一个包含另一个,我们令一个状态s的父状态 fas 为满足right集合包含s且right集合大小最小的状态,那么所有状态会形成一个树结构
显然初始态的right集合是1~n的所有整数,所有叶子结点的集合大小为1,也就是说叶节点个数 O(n) ,一个非叶子结点至少有两个儿子,因此后缀自动机的状态数是 O(n)
转移数线性
考虑SAM的一个从初始结点开始的树形图,显然树形图上边的数量是 O(n) 的,而对于一个非树边u->v来说,我们从初始状态->u->v->end,可以找到一个后缀,对于每一个后缀,我们将它对应于它经过的第一条非树边,那么所有非树边都会被覆盖,因此后缀自动机的转移数是 O(n)

构造算法

我们采取增量法来构造SAM
对于每个状态s,记它代表的最长子串的长度为 lens
考虑我们已经有了前LEN-1个字符的后缀自动机,现在自动机中串S[1,LEN-1]位与状态last,现在加入第LEN个字符c,那么我们新建一个状态np,令np=LEN
之后考虑更新转移边,显然我们应该加入一个last->np的转移,一个 falast>np 的转移,直到我们发现这个状态已经有了一个字符c的转移,不妨设这个状态是p,设它经过字符c的转移后的状态为q
这时q的表示的字符串集合中需要增加一个右端点为LEN,长度为len_{p}+1的串,但这时候我们不能直接把np挂在q的下面
对于q中长度不超过 lenp+1 来说,它们的right集合中会多出一个LEN,而对于长度大于 lenp+1 的串来说,它们的right集合不变,因此我们分裂出一个新的状态 nq ,代表q中长度不超过 lenp+1 的串,right集合为 rightq+len ,其它属性与原q点一致(fa和转移),这样q和np的right集合就都包含与nq中了,于是我们令 faq=fanp=nq
再从p开始,如果p的c字符转移到的是点q,现在转移到nq,如果 fap 的c字符转移到的是点q,那么它现在转移到nq……直到发现当前结点转移到的不是q为止

基本性质

性质一
每个状态s表示的串的长度的区间是( lenfa,lens )

性质二
每个状态s表示的所有串在原串中的出现次数以及每次出现的右端点相同

性质三
在parent树中,每个状态的right集合是它的父状态的right集合的子集

right集合

要求right集合,只要把 prei 所在的结点的right集合设成 i <script type="math/tex" id="MathJax-Element-256">i</script>再按bfs的逆序将每个状态的right集合并入它父亲的right集合即可,可以使用平衡树来维护,合并时采取启发式合并

Parent树

性质四
后缀自动机的parent树是原串的反串的后缀树
(后缀树就是把一个子串的后缀插入Trie中把不分支的链合并)
这个性质比较显然,考虑一个前缀在自动机上的状态,每次沿着fa指针走,每次会变成当前串的一个后缀,直到空串,相当于在反串的后缀树上从上往下走
求出初始串的反串的后缀自动机,它的parent树就是原串的后缀树
对后缀树dfs序就可以求出后缀数组

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值