spoj Longest Common Substring II
Longest Common Substring II
求10个串的LCS
/* 1、用第一个串建立后缀自动机 2、len[s] 表示状态s 所能代表的字符串的最大长度 mx[s] 表示状态s 在 当前匹配的串的最长匹配后缀长度 ans[s] 表示状态s 在所有串的最长匹配后缀长度 3、用第2——第10个串在后缀自动机上跑,每次mx[s]=max(mx[s],当前匹配长度) 每一个串跑完之后,更新 ans[s]=min(ans[s],mx[s]) 4、每次匹配完一个字符串的时候,要 从后缀自动机 parent 树 上的叶子节点 向根更新, 因为后缀自动机的parent树上,min[s]=max(fa[s])+1,所以子节点能匹配的长度 比 父节点的max要长。父节点是子节点的后缀,父节点可以匹配子节点的后max(fa[s])位,但是在那串在后缀自动机上跑的时候,不能保证经过 s 的 时候 也经过了s到根的链。所以只要子节点s 有匹配长度,父节点的mx[fa[s]]即可修改为len[fa[s]]即max(fa[s]) */ #include<iostream> #include<cstdio> #include<cstring> #define maxn 100010 using namespace std; char s[maxn]; int len[maxn<<1],ch[maxn<<1][26],fa[maxn<<1],sz=1,last=1,p,q,np,nq; int c[maxn],sa[maxn<<1],mx[maxn<<1],ans[maxn<<1]; void Insert(int c){ np=++sz; len[np]=len[last]+1; ans[sz]=len[sz]; p=last; while(p&&!ch[p][c])ch[p][c]=np,p=fa[p]; if(!p)fa[np]=1; else { q=ch[p][c]; if(len[q]==len[p]+1)fa[np]=q; else { nq=++sz; memcpy(ch[nq],ch[q],sizeof(ch[q])); fa[nq]=fa[q]; fa[q]=fa[np]=nq; ans[nq]=len[nq]=len[p]+1; while(ch[p][c]==q)ch[p][c]=nq,p=fa[p]; } } last=np; } void solve(){ int l,c,now,nowlen,x; while(scanf("%s",s+1)!=EOF){ l=strlen(s+1); now=1;nowlen=0; for(int i=1;i<=l;i++){ c=s[i]-'a'; while(now&&!ch[now][c]){ now=fa[now]; nowlen=len[now]; } if(!now){ nowlen=0; now=1; } else if(ch[now][c]){ nowlen++; now=ch[now][c]; } mx[now]=max(mx[now],nowlen); } for(int i=sz;i;i--){ x=sa[i]; ans[x]=min(ans[x],mx[x]); if(fa[x]&&mx[x])mx[fa[x]]=len[fa[x]]; mx[x]=0; } } int Ans=0; for(int i=1;i<=sz;i++)Ans=max(Ans,ans[i]); printf("%d",Ans); } int main(){ freopen("Cola.txt","r",stdin); scanf("%s",s+1); int l=strlen(s+1); for(int i=1;i<=l;i++)Insert(s[i]-'a'); for(int i=1;i<=sz;i++)c[len[i]]++; for(int i=1;i<=l;i++)c[i]+=c[i-1]; for(int i=sz;i;i--)sa[c[len[i]]--]=i; solve(); return 0; }