1. 程式人生 > >cv3160 最長公共子串(SAM)

cv3160 最長公共子串(SAM)

題目連結

分析:
A串建立一個SAM
B串在SAM上匹配
能匹配到的最遠結點(到root的距離)就是最長公共子串

如果匹配不上的時候,我們直接通過parent跳到ta的“失配”上

tip

雖然SAM的空間是O(n),但是在開陣列的時候是大小要到n2

#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

const int N=100003;
int ch[N<<1][26],fa[N<<1
],sz=1,last=1,root=1,dis[N<<1]; char a[N],b[N]; void insert(int x) { int pre=last,now=++sz; last=now; dis[now]=dis[pre]+1; for (;pre&&!ch[pre][x];pre=fa[pre]) ch[pre][x]=now; //找Parent樹上有沒有這個結點 if (!pre) fa[now]=root; else { int q=ch[pre][x]; //找了一個祖先
if (dis[q]==dis[pre]+1) fa[now]=q; else { int nows=++sz; dis[nows]=dis[pre]+1; memcpy(ch[nows],ch[q],sizeof(ch[nows])); fa[nows]=fa[q]; fa[now]=fa[q]=nows; for (;pre&&ch[pre][x]==q;pre=fa[pre]) ch[pre][x]=nows; } } } void
solve() { int len=strlen(b+1),ans=0,now=root,tmp=0; for (int i=1;i<=len;i++) { int x=b[i]-'a'; if (ch[now][x]) now=ch[now][x],tmp++; else { while (now&&!ch[now][x]) now=fa[now]; if (!now) now=1,tmp=0; else { tmp=dis[now]+1; now=ch[now][x]; } } ans=max(ans,tmp); } printf("%d",ans); } int main() { scanf("%s",a+1); scanf("%s",b+1); for (int i=1;i<strlen(a+1);i++) insert(a[i]-'a'); solve(); return 0; }