最長公共子串 字尾自動機
阿新 • • 發佈:2019-02-07
【題目描述】
給定兩個字串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; }