P5546 [POI2000]公共串
询问多个串的最长公共子串。
利用 SAM 的 ACAM 的性质,先把每个串拿来匹配,然后沿途打标记,每次更新完一个串再更新一下对于全局的答案。
最后求出每个节点匹配的最大长度即可。
代码:
#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
x=0;char ch=getchar();bool f=false;
while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return ;
}
template <typename T>
inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10^48);
return ;
}
const int N=3e5+5,INF=1e9+7;
int x,n,last=1,tot=1,Ans[N<<1],AAns[N<<1],ans,c[N],q[N<<1];
bool flag;
char str[N];
struct SAM{
int son[26];
int fa,len;
}t[N<<1];
void Extend(int c){
int p=last,np=++tot;last=np;
t[np].len=t[p].len+1;
while(p&&!t[p].son[c]) t[p].son[c]=np,p=t[p].fa;
if(!p) t[np].fa=1;
else{
int q=t[p].son[c];
if(t[p].len+1==t[q].len) t[np].fa=q;
else{
int nq=++tot;
t[nq]=t[q];t[nq].len=t[p].len+1;
t[np].fa=t[q].fa=nq;
while(p&&t[p].son[c]==q) t[p].son[c]=nq,p=t[p].fa;
}
}
return ;
}
int Len;
void Search(int &x,int c){
if(t[x].son[c]) Len++,x=t[x].son[c],AAns[x]=max(AAns[x],Len);
else{
int p=x;
while(p&&!t[p].son[c]) p=t[p].fa;
if(!p) x=1,Len=0;
else x=t[p].son[c],Len=t[p].len+1,AAns[x]=max(AAns[x],Len);
}
return ;
}
int main(){
read(n);
scanf("%s",str);int len=strlen(str);
for(int i=0;i<len;i++) Extend(str[i]-'a');
for(int i=1;i<=tot;i++) c[t[i].len]++;
for(int i=1;i<=tot;i++) c[i]+=c[i-1];
for(int i=1;i<=tot;i++) q[c[t[i].len]--]=i;
for(int i=0;i<=tot;i++) Ans[i]=INF;
n--;
while(n--){
scanf("%s",str);
len=strlen(str);Len=0;
for(int i=0,now=1;i<len;i++) Search(now,str[i]-'a');
for(int i=tot;i>=1;i--){
int x=q[i];
AAns[t[x].fa]=max(AAns[t[x].fa],min(AAns[x],t[t[x].fa].len));
Ans[x]=min(Ans[x],AAns[x]);AAns[x]=0;
}
}
for(int i=1;i<=tot;i++) ans=max(ans,Ans[i]);
write(ans);
return 0;
}