SAM学习笔记

并没有完全理解,处于只会板子阶段。

SAM 就是后缀自动机,比较为大众所接受的定义是:一个接受 s s s 所有后缀的最小自动机。

什么是自动机

比较通俗的说法是一张 DAG ,有一个起始点,路径上有字符。(定义是什么并不重要)。

SAM 的定义是,从起始点走到每个节点一定是原串的一个子串,并且全部子串都在里面。至于为什么会跟子串问题产生关系,先来看看什么事后缀 trie.

后缀 trie/后缀树

问题:求一个字符串本质不同的子串数量。

解法:后缀 trie,插入 S 的所有后缀,从根节点到 trie 每个节点都是一个子串且互不相同。

证明:这不是显然吗。

很不幸,这玩意 O ( n 2 ) O(n^2) O(n2) 的。

考虑一条链其实可以缩成一个点,并不影响树的形态。这就是后缀树。

但是后缀树怎么建呢。掏出一个 SAM。

SAM

先引入一个叫 e n d p o s endpos endpos 的概念。对于一个字符串 S S S e n d p o s ( S ) endpos(S) endpos(S) 就是它在原串中所有匹配的串的末尾的位置的集合。

SAM 的每一个点实质上是代表一个 e n d p o s endpos endpos 相同的所有后缀。

那么,容易看出对于两个 e n d p o s endpos endpos 集合,要么包含,要不不交。并且一个 e n d p o s endpos endpos 中小的一定是大的的后缀。

那么我们定义 l e n i len_i leni 表示 SAM i i i 号点代表的最长后缀的长度。既然只有包含关系,我们把每个点的父亲设为包含它 l e n len len 最小的。

考虑增量构造一个 SAM,即每次插入一个字符,然后考虑它的贡献,首先新增一些后缀,比如原来是 aabba 加入一个 a ,新增了 aa,baa,bbaa,abbaa,aabbaa 这些。然后这些肯定有已经出现过的,如果一个出现过,那它所有后缀肯定也都出现过,我们只需要找第一个没出现过的(换而言之,最后一个出现的)。

首先找到上一个对应的 SAM 上的点,开始跳 fa,我们定义 ch[i][c] 表示 SAM 上一点连边情况(类似于 trie),直到跳到一个点它 ch[i][c] 是有值的。

在这里不妨先讨论下跳 fa 的本质,既然完全包含,那么 fa 集合任意字符串一定是儿子集合的后缀。

找到那个点 p p p 之后,分类讨论。

1° 没找着
直接跟 rt 连。
l e n c h [ p ] [ c ] = l e n p + 1 len_{ch[p][c]}=len_{p}+1 lench[p][c]=lenp+1
正好中间没有压缩,直接连 ch[p][c]
3° otherwise
这就比较麻烦了。

c h [ p ] [ c ] ch[p][c] ch[p][c] 不再是它的父亲,而包含了一些杂七杂八的东西,这时候就得把它分裂了。

新建一个节点 n q nq nq,作为 n p , c h [ p ] [ c ] np,ch[p][c] np,ch[p][c] 的父亲。然后继承 c h [ p ] [ c ] ch[p][c] ch[p][c] n p np np 有关的信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值