SPOJ-LCS 后缀自动机
题意:给出两个$n=250000$的字符串,求最长公共子串。
思路:把第一个字符串放到SAM里面去。
对于第二个串,能匹配则匹配,不能匹配就跳回能匹配的位置,如果一个都不能匹配,则cur要重新初始化为root。
对后缀自动机的理解还比较模糊,怕误人子弟,此题就不做详述。
#include<bits/stdc++.h> #define clr(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int maxn=250010*2; char s1[maxn],s2[maxn]; int len1,len2,len[maxn],tot=1,root=1,last=1,ch[maxn][27],fa[maxn]; void extend(int x){ int now=++tot,pre=last; last=now,len[now]=len[pre]+1; while( pre && !ch[pre][x]){ ch[pre][x]=now; pre=fa[pre]; } if(!pre)fa[now]=root; else{ int q = ch[pre][x]; if(len[q]==len[pre]+1)fa[now]=q; else{ int nows = ++tot; memcpy(ch[nows],ch[q],sizeof(ch[q])); len[nows]=len[pre]+1; fa[nows]=fa[q]; fa[q]=fa[now]=nows; for(;pre && ch[pre][x] == q;pre=fa[pre]){ ch[pre][x]=nows; } } } } int main(){ scanf("%s",s1); scanf("%s",s2); len1=strlen(s1); len2=strlen(s2); for(int i=0;i<len1;i++) { int p=s1[i]-'a'; extend(p); } int maxx=0,cur=root,ans=0; for(int i=0;i<len2;i++,ans=max(maxx,ans)) { int p=s2[i]-'a'; if(ch[cur][p]){ cur=ch[cur][p]; maxx++; continue; } while(cur&&ch[cur][p]==0){ cur=fa[cur]; } if(cur){ maxx=len[cur]+1; cur=ch[cur][p]; }else{ cur=1; maxx=0; } } printf("%d\n",ans); }
——愿为泰山而不骄
qq850874665~~