1. 程式人生 > >spoj LCS2 - Longest Common Substring II && LCS - Longest Common Substring

spoj LCS2 - Longest Common Substring II && LCS - Longest Common Substring

const ima space poj 集合 scanf cst printf common

多串LCS很適合SA但是我要學SAM
對第一個串求SAM,然後把剩下的串在SAM上跑,也就是維護p和len,到一個點,如果有ch[p][c],就p=ch[p][c],len++,否則向fa找最下的有c[p][c]的p,然後len=dis[p]+1,p=ch[p][c],否則就p=root,len=0(這個len每到一個節點就更新這個節點的f)
然後註意到在parent樹上,因為每個節點代表的right集合是兒子的並集,所以f[u]是可以更新f[fa[u]]的,所以從底向上更新一遍(註意先更新!!)
最終點u的f就是每個串的f與dis[u]取min,然後ans在這些點上取max
技術分享圖片
技術分享圖片
技術分享圖片
技術分享圖片
cpp #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=500005; int n,m=1,fa[N],ch[N][27],dis[N],cur=1,con=1,la,f[N][15],c[N],a[N],ans; char s[N]; void ins(int c,int id) { la=cur,dis[cur=++con]=id; int p=la; for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur; if(!p) fa[cur]=1; else { int q=ch[p][c]; if(dis[q]==dis[p]+1) fa[cur]=q; else { int nq=++con; dis[nq]=dis[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[q])); fa[nq]=fa[q]; fa[q]=fa[cur]=nq; for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq; } } } int main() { scanf("%s",s+1); n=strlen(s+1); for(int i=1;i<=n;i++) ins(s[i]-‘a‘,i); for(int i=1;i<=con;i++) f[i][1]=dis[i]; while(~scanf("%s",s+1)) { n=strlen(s+1),m++; for(int i=1,p=1,len=0;i<=n;i++) { int c=s[i]-‘a‘; if(ch[p][c]) len++,p=ch[p][c],f[p][m]=max(f[p][m],len); else { for(;p&&!ch[p][c];p=fa[p]); if(!p) p=1,len=0; else len=dis[p]+1,p=ch[p][c],f[p][m]=max(f[p][m],len); } } } for(int i=1;i<=con;i++) c[dis[i]]++; for(int i=1;i<=con;i++) c[i]+=c[i-1]; for(int i=1;i<=con;i++) a[c[dis[i]]--]=i; for(int j=2;j<=m;j++) for(int i=con;i>=1;i--) f[fa[a[i]]][j]=max(f[fa[a[i]]][j],f[a[i]][j]); for(int i=1;i<=con;i++) { for(int j=2;j<=m;j++) f[i][1]=min(f[i][1],f[i][j]); ans=max(ans,f[i][1]); } printf("%d\n",ans); return 0; }

技術分享圖片

spoj LCS2 - Longest Common Substring II && LCS - Longest Common Substring