最长公共子串 后缀自动机

来源:互联网 发布:电子券怎么在淘宝使用 编辑:程序博客网 时间:2024/06/05 19:23

【题目描述】

给定两个字符串A和B,求它们的最长公共子串

【分析】

我们考虑将A串建成后缀自动机

令当前状态为s,同时最大匹配长度为len

我们读入字符x。如果s有标号为x的边, 那么s=trans(s,x),len = len+1

否则我们找到s的第一个祖先a,它有标号为x的边,令 s=trans(a,x),len=Max(a)+1。

如果没有这样的祖先,那么令s=root,len=0。

在过程中更新状态的最大匹配长度

注意到我们求的是对于任意一个Right集合中的r,最大的匹配长度。那么对于一个状态s,它的结果自然也可以作为它Parent的结果,我们可以从底到上更新一遍。

然后问题就解决了。

———来自陈立杰《后缀自动机讲稿》

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<ctime>#include<cmath>#include<algorithm>using namespace std;#define FILE "read"#define MAXN 200010#define up(i,j,n) for(int i=j;i<=n;++i)#define dn(i,j,n) for(int i=j;i>=n;--i)#define cmax(a,b) a=max(a,b)#define cmin(a,b) a=min(a,b)char ch[MAXN];int n,cnt(1),now(1),len,ans,mx[MAXN],par[MAXN],son[MAXN][27];void insert(int x){int p=now,np=++cnt;mx[np]=mx[now]+1;  now=np;while(p&&!son[p][x]) son[p][x]=np,p=par[p];if(!p) par[np]=1;else{int q=son[p][x];if(mx[q]==mx[p]+1) par[np]=q;else{int nq=++cnt;mx[nq]=mx[p]+1;memcpy(son[nq],son[q],sizeof(son[q]));par[nq]=par[q];par[q]=par[np]=nq;while(p&&son[p][x]==q)son[p][x]=nq,p=par[p];}}}int walk(int x){while(!son[now][x]&&par[now]){now=par[now];len=mx[now];}if(!son[now][x]) return 0;now=son[now][x];  len++;return len;}int main(){freopen(FILE".in","r",stdin);freopen(FILE".out","w",stdout);scanf("%s",ch+1);  n=strlen(ch+1);up(i,1,n)  insert(ch[i]-'a');scanf("%s",ch+1);  n=strlen(ch+1);  now=1;up(i,1,n)  cmax(ans,walk(ch[i]-'a'));printf("%d\n",ans);return 0;}


0 0