SAM
前言
你可能需要先看一看前面两篇文章。
然后对于AC自动机这个知识点,博主在几百万年前学过一次,但现在已经忘得差不多了,但还是有一些理解的,所以不确定没学过AC自动机的OIer能否理解本文。
(真会有人和作者一样先学SAM吗?)
本文将结合例题进行具体的讲解。
6. 讲解
还是简单讲解一下AC自动机吧。
可以理解为在 Trie 上做 kmp。而其中的精髓是 fail 指针。
状态 u u u 的 fail 指针指向另一个状态 v v v,其中 v v v 是 u u u 的最长后缀(即在若干个后缀状态中取最长的一个作为 fail 指针),也就是把前面去掉(尽可能少的)一点。
我们注意到 SAM 的 f f f 指针(或者叫 l i n k link link)有同样的性质:儿子是由父亲在前面加字符产生的,那么父亲就可以视作在儿子前面去掉字符。
我们完全可以把 SAM 理解为把某个串的所有子串建立AC自动机,于是在SAM上硬跑匹配。
而SAM处理字符串匹配在 5.2 5.2 5.2 已经讲过了,这里搬张图过来:

6.1 最长公共子串
题意:输入两个字符串,输出它们的最长公共子串长度,若不存在公共子串则输出 0 0 0。
其中字符串长度不超过 2.5 × 1 0 5 2.5\times 10^5 2.5×105
我们把两个串分别称作 s 1 , s 2 s1,s2 s1,s2
对于 s 2 s2 s2 设一个数组为 s l e n [ i ] slen[i] slen[i]
s l e n [ i ] slen[i] slen[i] 表示 s 1 s1 s1 中 s 1 [ i − s l e n [ i ] + 1 , i ] s1[i−slen[i]+1,i] s1[i−slen[i]+1,i] 在 s 2 s2 s2 中出现过,即以 i i i 结尾的位置的最长匹配长度。
s l e n slen slen 数组的实际意义是每个前缀匹配出的最长后缀,不难发现 s l e n slen slen 数组的 max \max max 就是答案。
代码:
#include<bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;
const int N=3e5+1;
ll ans;
int slen[N];
struct SAM{
int las,tn;
int sz[N<<1];
SAM(){
las

最低0.47元/天 解锁文章
44

被折叠的 条评论
为什么被折叠?



