定义
一个串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序就可以求出后缀数组