后缀自动机ヾ(*////▽////*)ゞ

后缀自动机

在后缀自动机之前还需要一些前置知识。

End pos 集合

即结束的位置集合,简称 E p Ep Ep 集合,代表一个子串在原串中出现的右端点。例如在下面这个字符串:

ZHOUSHENNISHISHENMEJUESHIDABAOBEI

这些加粗的 S H SH SH的右端点的位置分别是 6 , 12 , 15 , 24 6,12,15,24 6,12,15,24,那么在这个字符串里, S H SH SH E p Ep Ep 集合就是 { 6 , 12 , 15 , 24 } \{6,12,15,24\} {6,12,15,24}
E p Ep Ep 相同的子串叫一个等价类。

llen 和 lstr

l l e n llen llen表示 l o n g e s t l e n t h longest lenth longestlenth l s t r lstr lstr表示 l o n g e s t s t r i n g longest string longeststring
对一个 E p Ep Ep 等价类,满足这个的等价类最长子串就是这个 E p Ep Ep 等价类的 l s t lst lstr, l s t r lstr lstr 的长度就是 l l e n llen llen
例如,对于前面那个字符串, E p Ep Ep 集合为 { 6 , 12 , 15 , 24 } \{6,12,15,24\} {6,12,15,24} l s t r lstr lstr就是 S H SH SH l l e n llen llen就是 8 8 8

后缀自动机

以字符串 a a b b a b d aabbabd aabbabd 举例。

a a b b a b d aabbabd aabbabd 的所有后缀建树。
在这里插入图片描述
再将没有分支的链缩成点:
在这里插入图片描述
再将每个节点指向它的 f a i l fail fail f a i l [ x ] fail[x] fail[x] x x x 在后缀树上的父亲):
在这里插入图片描述
构建后缀自动机伪代码如下:

int sam_add(char c){
	v=上次加入的点的编号;
	u=++tot;
	u为加入的点
    v一直连边,直到遇到有一条字符为c的出边的点x
    y=x的出边
    if(!x) return fa[u]=1;
    if(len[x]+1==len[y]) return fa[u]=y;
    else{
    	新建点p
		llen[p]=llen[x]+1;
		fa[p]=fa[y];
		fa[u]=fa[y]=p
        设好p的出边
    	找到p的入边
	}	     
}

基本应用

  • 求一个字符串有多少个本质不同的子串。
  • 求一个字符串有多少个包含某个字符串 T T T的本质不同的子串。
  • 求每个前缀/后缀的本质不同子串个数
  • 求两个串 S , T S,T S,T 的最长公共子串
  • L C P ( S [ i , n ] , S [ j , n ] ) LCP(S[i,n], S[j,n]) LCP(S[i,n],S[j,n])
  • 求第 k k k 小子串的值(本质不同/本质相同)
  • 求一个子串的出现次数
  • 不重叠最长重复子串

例题

基础题

  1. 给定 S , T S,T S,T,求他们有几对子串相同。
  2. n n n 个字符串,求有多少个子串是其中至少 k k k 个字符串的子串。
  3. ∑ ( l c p ( i , j ) ) \sum(lcp(i,j)) (lcp(i,j))
  4. 求长度为 k k k 的字典序最小的子串。
  5. 给出字符串 s s s,数组 a a a 和整数 k k k,你需要选出两个不同的后缀 i i i j j j 使得它们的 l c p lcp lcp 长度大于等于 k k k 同时最大化 a i ∗ a j a_i*a_j aiaj

Fim1

题目简述:给定一个字符串 S S S,维护一个字符串序列 T T T。其中, T . a p p e n d ( T [ x ] + c ) ; T . a p p e n d ( c + T [ x ] ) T.append(T[x]+c);T.append(c+T[x]) T.append(T[x]+c);T.append(c+T[x])
询问T[x]在S[l,r]中出现的次数。

[BZOJ4556]字符串

题目简述:给定一个字符串,有 Q Q Q 次询问,每次给出 [ a , b ] [ c , d ] [a,b][c,d] [a,b][c,d],询问 s [ a , b ] s[a,b] s[a,b] 的所以子串 s [ c , d ] s[c,d] s[c,d] 的最长公共前缀的最大值。

[CF700E]Cool Slogans

题目传送门
题目简述:给定一个字符串 S S S,要求构造字符串序列 s 1 , s 2 , . . . , s k s_1,s_2,...,s_k s1,s2,...,sk,满足任意 s i s_i si 都是 S S S 的子串,且任意 i ∈ [ 2 , n ] i\in[2,n] i[2,n],都有 s i − 1 s_{i-1} si1 s i s_i si 中出现了至少 2 2 2 次(可以有重叠部分,只要起始、结尾位置不同即可)。 求可能的最大的 k k k 的值(即序列的最大可能长度)。

NSUBSTR-Substrings

题目传送门
题目简述:给出一个字符串,对于每个 k k k,求出所有长度为 k k k 的子串中出现次数的最大值。

[TJOI2016]字符串

题目传送门
题目简述:给出一个字符串,有 m m m 次询问,每次询问子串 [ a , b ] [a, b] [a,b] 的所有子串中与子串 [ c , d ] [c, d] [c,d] L C P LCP LCP 最大值是多少。


广义后缀自动机

即根据多个串建自动机。
其中 a d d add add 部分与一般的后缀自动机一样。
用所有模式串建出一颗 t r i e trie trie 树,对其进行 d f s / b f s dfs/bfs dfs/bfs 遍历构建后缀自动机,在 i n s e r t insert insert 时使 l a s t last last 为它在 t r i e trie trie 树上的父亲,其余和普通后缀自动机一样。

d f s dfs dfs 代码如下:

void dfs(int x){
    for(int i=0;i<26;i++){
    	int y=tr[x][i];
    	if(y) pos[y]=insert(c[y],pos[x]),dfs(y);
	}
}
void build(){pos[1]=1,dfs(1);}

b f s bfs bfs 代码如下:

void build(){
    for(int i=0;i<C;i++)
		if(tr[1][i]) q.push(tr[1][i]);
    pos[1]=1;
    while(!q.empty()){
        int x=q.front();q.pop();
        pos[x]=insert(c[x],pos[fa[x]]);
        for(int i=0;i<C;i++)
			if(tr[x][i]) q.push(tr[x][i]);
    }
}

例题

Codechef TSUBSTR

题目简述:一棵trie,考虑所有从上往下的串。多组询问,每次询问给你一个字典序,问你字典序第k大的串。

[ZJOI2015]幻想乡

题目传送门
题目简述:给一个叶子数不超过 20 20 20 t r i e trie trie,求有多少个不同的子串。

[BZOJ4545]DQS的Trie

题目简述:一颗 t r i e trie trie 树, q q q 次操作,操作有 3 3 3 种:
1.求这棵树上本质不同的子串数量。
2.插入一个子树,保证总大小不超过 100000 100000 100000
3.询问一个字符串在 t r i e trie trie 树上出现过多少次,保证所有询问串总长度不超过 100000 100000 100000

[NOI2018]你的名字

题目传送门
题目简述:给一个 S S S,每次问 T T T有多少个本质不同的子串不是 S [ l … r ] S[l…r] S[lr]的子串。

无题

题目简述:有一颗树,节点上带字母。每次给出一个串和一条路径,问这个串在这条路径上出现了几次。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值