SPOJ1811 后缀自动机入门
题目链接:点我点我:-)
题目描述:
求两个字符串的最长公共子串的长度,字符串长度小于等于
输入格式:
两行即两个字符串
输出格式:
一个整数,表示两个字符串的最长公共子串的长度
思路:
后缀自动机裸题,入门的一个好的讲解:传送门
感想:
还是有一些地方不是很理解,特别是匹配的时候有点乱(关于step的问题)
还有一个同学的习题锦集,可以去做一下:传送门
(ps: 下方程序中的Query函数并没有用)
代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define For(i, a, b) for(int i = (a); i <= (int)(b); ++i)
#define N (500000+5)
struct Suffix_Automaton{
char s[N];
int son[N][26], pre[N], step[N], root, last, Tot;
void Insert(char ch){
ch -= 'a';
int p = last, np = ++Tot;
step[np] = step[last]+1; last = np;
for(;p&&!son[p][ch]; p=pre[p]) son[p][ch] = np;
if(!p) pre[np] = root;
else{
if(step[p]+1 == step[son[p][ch]]) pre[np] = son[p][ch];
else{
int q = son[p][ch], nq = ++Tot;
pre[nq] = pre[q]; step[nq] = step[p]+1;
For(i, 0, 25) son[nq][i] = son[q][i];
pre[q] = pre[np] = nq;
for(;son[p][ch]==q; p=pre[p]) son[p][ch] = nq;
}
}
}
int Query(char *s){
int nc, now = root, len = strlen(s);
For(i, 0, len-1){
nc = s[i]-'a';
if(!son[now][nc]) return i;
now = son[now][nc];
}
return len;
}
}sat;
char s1[N], s2[N];
int main(){
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif
sat.root = sat.last = ++sat.Tot;
scanf("%s%s", s1, s2);
int len1 = strlen(s1), len2 = strlen(s2);
For(i, 0, len1-1) sat.Insert(s1[i]);
int ans = 0, len = 0, now = sat.root;
char ch;
For(i, 0, len2-1){
ch = s2[i]-'a';
if(sat.son[now][ch]) ++len, now = sat.son[now][ch];
else{
while(now && !sat.son[now][ch]) now = sat.pre[now];
if(!now) now = sat.root, len = 0;
else len = sat.step[now]+1, now = sat.son[now][ch];
}
ans = max(ans, len);
}
printf("%d\n", ans);
return 0;
}
Miaomiao❤ ++RP