LCS - Longest Common Substring
阿新 • • 發佈:2020-08-19
SP1811 LCS - Longest Common Substring
用 sam 進行字串匹配,建 s 的 sam,然後用 t 在 s 的 sam 上進行匹配,匹配過程中,沿著 Next 轉移往下走,如果失配,則沿著 link 連結往上跳,因為 link 連結是該節點的字尾,所以這樣跳就不會有遺漏,而且均攤下來跳字尾連結的總複雜度為\(O(n)\)因此不會超時。
// Created by CAD #include <bits/stdc++.h> using namespace std; const int maxn=(2e5+5e4+5)*2; namespace sam{ int len[maxn],link[maxn],Next[maxn][26]; int sz,last; void init(){ //記得初始化 sz=last=0; len[0]=0,link[0]=-1; } void insert(char c){ //插入字元 int now=++sz; len[now]=len[last]+1; int p=last; while(~p&&!Next[p][c-'a']){ Next[p][c-'a']=now; p=link[p]; } if(p==-1) link[now]=0; else{ int q=Next[p][c-'a']; if(len[p]+1==len[q]) link[now]=q; else{ int clone=++sz; len[clone]=len[p]+1; memcpy(Next[clone],Next[q],sizeof(Next[q])); link[clone]=link[q]; while(~p&&Next[p][c-'a']==q){ Next[p][c-'a']=clone; p=link[p]; } link[q]=link[now]=clone; } } last=now; } int solve(char *s,char *t){ int ans=0; int op=0,last=-1; int slen=strlen(s),tlen=strlen(t); int now=0; while(op<tlen){ int temp=0; while(op<tlen&&Next[now][t[op]-'a']){//如果匹配則沿著轉移走下去 now=Next[now][t[op]-'a']; temp=op-last; ans=max(ans,temp); op++; } if(temp==0) op++,last++; while(~link[now]&&!Next[now][t[op]-'a']) //一旦失配,則沿著字尾連結往上跳,直到跳到0或者再次匹配 now=link[now]; last+=temp-len[now]; } return ans; } } char s[maxn],t[maxn]; int main() { sam::init(); scanf("%s%s",s,t); int slen=strlen(s); for(int i=0;i<slen;++i) sam::insert(s[i]); printf("%d\n",sam::solve(s,t)); return 0; }