给最多10个长度不超过10W的串,求他们的最长公共子串。还是LCS的问题,只不过成了多个串求公共子串,拿来做SAM的入门题还是不错的。拿第一个串构造后缀自动机,每个状态新增两个变量n1,m1,分别是当前串匹配到当前状态时时的最长子串的长度,前k个串跑完后,在当前状态可能得到的最长公共子串长度。不好理解的一点就是每次匹配完之后,n1的值要从后向前,去更新父节点上的值,因为父节点上能接受的子串全部都是当前节点能接受的子串的后缀,如果不向前传递的话,父节点的m1就可能被更新成0,这样如果下面有一个子串被这个父节点接受的话,他的m1也无法被记录。
#include <cstdio> #include <iostream> #include <memory.h> #include <cmath> #include <algorithm> #include <string> #include <cstring> using namespace std; typedef long long ll; const int S=26; const int maxn=200000+1000; const int inf=maxn<<2; int len,tot,ans; int n,m; char str[maxn>>1],s[maxn>>1],ss[maxn>>1]; int c[maxn]; struct node { node *par,*go[S]; int m1,n1,val; int id; }que[maxn],*top[maxn],*tail,*root; inline int idx(char s) { return s-'a'; } struct SAM { int init() { memset(que,0,sizeof que); len=1; tot=0; root=&que[tot++]; ans=0; root->id=root->n1=root->m1=root->val=0; tail=root; } void add(int c,int l) { node *p=tail; node *np=&que[tot++]; np->id=tot-1; np->val=l; np->m1=l; //np->n1=0; while (p&&p->go[c]==NULL) p->go[c]=np,p=p->par; if (p==NULL) np->par=root; else { node *q=p->go[c]; if (p->val+1==q->val) np->par=q; else { node *nq=&que[tot++]; *nq=*q; nq->id=tot-1; nq->val=nq->m1=p->val+1; np->par=q->par=nq; while (p&&p->go[c]==q) p->go[c]=nq,p=p->par; } } tail=np; } void debug_suff() { for (int i=0; i<tot; i++) { for (int c=0; c<S; c++) if (que[i].go[c]) { cout<<que[i].id<<" "<<que[i].go[c]->id<<endl; } } } void debug_pre() { for (int i=1; i<tot; i++) { cout<<que[i].id<<" "<<que[i].par->id<<endl; } } inline void TopS() { memset(c,0,sizeof c); for (int i=0; i<tot; i++) c[que[i].val]++; for (int i=1; i<=len; i++) c[i]+=c[i-1]; for (int i=0; i<tot; i++) { top[--c[que[i].val]]=&que[i]; } } void slove() { ans=0; while(~scanf("%s",s)) { int l=strlen(s); node *p=root; int tmp=0; for (int i=0; i<l; i++) { int x=idx(s[i]); if (p->go[x]!=NULL) { tmp++; p=p->go[x]; } else { while(p&&p->go[x]==NULL)p=p->par; if (p==NULL) tmp=0,p=root; else { tmp=p->val+1; p=p->go[x]; } } if (tmp>p->n1) p->n1=tmp; } for (int i=tot-1; i>=0; i--) { p=top[i]; if (p->n1<p->m1) p->m1=p->n1; if (p->par && p->par->n1<p->n1) p->par->n1=p->n1; p->n1=0; } } for (int i=0; i<tot; i++) ans=max(ans,que[i].m1); } }sam; int main() { // freopen("in.txt","r",stdin); scanf("%s",str); int l=strlen(str); sam.init(); for (int i=0; i<l; i++) sam.add(idx(str[i]),len++); sam.TopS(); sam.slove(); printf("%d\n",ans); return 0; }