题目描述 Description
给出两个由小写字母组成的字符串,求它们的最长公共子串的长度。
输入描述 Input Description
读入两个字符串
输出描述 Output Description
输出最长公共子串的长度
样例输入 Sample Input
yeshowmuchiloveyoumydearmotherreallyicannotbelieveit
yeaphowmuchiloveyoumydearmother
样例输出 Sample Output
27
数据范围及提示 Data Size & Hint
单个字符串的长度不超过100000
题解:后缀自动机。
对其中的一个串建立后缀自动机,然后用另一个串在自动机上匹配。类似在AC自动机上的匹配过程,匹配不上了跳转到parent指针(指的是记录的是上一个可以接收后缀的结点(如果当前结点可以接收新的后缀,那么parent指向的结点也一定可以接收后缀)),然后进行匹配。另外l[i]记录的是从根节点到当前节点的最长距离。
匹配上的最长的长度即为最长公共子串。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 200003
using namespace std;
int n,m,ch[N][30],fa[N],a[N],l[N],np,nq,p,q,last,cnt,root;
char s[N],s1[N];
void extend(int x)
{
int c=a[x];
p=last; np=++cnt; last=np;
l[np]=x;
for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
if (!p) fa[np]=root;
else {
int q=ch[p][c];
if (l[p]+1==l[q]) fa[np]=q;
else {
int nq=++cnt; l[nq]=l[p]+1;
memcpy(ch[nq],ch[q],sizeof ch[nq]);
fa[nq]=fa[q];
fa[np]=fa[q]=nq;
for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
}
}
}
int solve()
{
int tmp=0,ans=0;
for (int i=1;i<=m;i++) {
int c=s1[i]-'a';
if (ch[p][c]) p=ch[p][c],tmp++;
else {
while (p&&!ch[p][c]) p=fa[p];
if (!p) p=1,tmp=0;
else {
tmp=l[p]+1;
p=ch[p][c];
}
}
ans=max(ans,tmp);
}
return ans;
}
int main()
{
freopen("a.in","r",stdin);
scanf("%s",s+1);
n=strlen(s+1); last=root=++cnt;
for (int i=1;i<=n;i++) a[i]=s[i]-'a';
for (int i=1;i<=n;i++) extend(i);
scanf("%s",s1+1);
m=strlen(s1+1);
printf("%d",solve());
}