【题目大意】
求N(N<=10)个串的最长公共子串,每个串长度10w。
【分析】
依旧构造第一个串的后缀自动机,用其余字符串与其匹配。
除了记录与当前字符串成功匹配的位置和位数以外,要在每个节点上记录到上一个串为止、在该节点处能够成功匹配的最长位数。并且根据性质,那些被当前已匹配串所包含的串也是可以成功匹配的,所以还需要沿着后缀链接向前实时更新。
【代码】
/************************
ID:Ciocio
LANG:C++
DATE:2014-1-28
TASK:LCS
************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
#define MAXN 100010
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rrep(i,a,b) for(int i=a;i>=b;--i)
char A[MAXN];
int ans;
struct SAM{
int tot,last,idx;
int pre[MAXN<<1],go[MAXN<<1][26],step[MAXN<<1];
int f[15][MAXN<<1];
void new_node(int s){
step[++tot]=s;
pre[tot]=0;
memset(go[tot],0,sizeof go[tot]);
}
void build(char* s){
tot=0;last=1;
new_node(0);
int n=strlen(s);
rep(i,0,n-1){
new_node(step[last]+1);
int c=s[i]-'a';
int p=last,np=tot,q,nq;
for(;p&&!go[p][c];p=pre[p]) go[p][c]=np;
if(!p)
pre[np]=1;
else{
q=go[p][c];
if(step[q]==step[p]+1) pre[np]=q;
else{
new_node(step[p]+1);
nq=tot;
memcpy(go[nq],go[q],sizeof go[q]);
pre[nq]=pre[q];
pre[np]=
pre[q]=nq;
for(;p&&go[p][c]==q;p=pre[p]) go[p][c]=nq;
}
}
last=np;
}
rep(i,1,tot) f[0][i]=step[i];
}
void match(char* s){
idx++;
int p=1,len=0;
int n=strlen(s);
rep(i,0,n-1){
int c=s[i]-'a';
while(pre[p]&&!go[p][c]){
p=pre[p];
len=step[p];
}
if(go[p][c]){
p=go[p][c];
len++;
f[idx][p]=max(f[idx][p],min(f[idx-1][p],len));
for(int i=pre[p];pre[i];i=pre[i]){
if(f[idx][i]>=f[idx-1][i]) break;
f[idx][i]=f[idx-1][i];
}
}
}
int tmp=0;
rep(i,1,tot) tmp=max(tmp,f[idx][i]);
ans=tmp;
}
};
SAM run;
int main(){
scanf("%s",A);
run.build(A);
while(~scanf("%s",A)){
run.match(A);
if(!ans) break;
}
cout<<ans<<endl;
return 0;
}