题意:
求n个字符串的最长公共子串的长度
题解:
这个题可以类比只有两个字符串的情况来做。
我们仍然选择对第一个字符串建立SAM,然后对于其他串在SAM上匹配,过程中记录一下每个字符串到达SAM中某个节点时的长度,对于每个状态取
m
i
n
min
min,然后从最小值中选取最大值即为答案。
A C AC AC代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5+50;
const int INF = 0x3f3f3f3f;
char s[MAXN],ss[MAXN];
struct Suffix{
int nxt[MAXN][26],fa[MAXN],len[MAXN];
int c[MAXN],a[MAXN],l[MAXN],res[MAXN];
int last=1,tot=1;
inline void Insert(int x){
int p = last,np = ++tot;
last = np,len[np] = len[p] + 1;
for(;p && !nxt[p][x];p=fa[p]) nxt[p][x] = np;
if(!p) fa[np] = 1;
else {
int q = nxt[p][x];
if(len[p]+1 == len[q]) fa[np] = q;
else {
int nq = ++tot;
len[nq] = len[p] + 1;
memcpy(nxt[nq],nxt[q],sizeof(nxt[q]));
fa[nq] = fa[q];
fa[q] = fa[np] = nq;
for(;nxt[p][x]==q;p=fa[p])
nxt[p][x] = nq;
}
}
}
inline void Sort(int n){
for(int i=1;i<=tot;i++) c[len[i]]++;
for(int i=1;i<=n;i++) c[i]+=c[i-1];
for(int i=1;i<=tot;i++) a[c[len[i]]--]=i;
memset(res,INF,sizeof(res));
}
inline void Solve(int n){
int p = 1,ans = 0;
memset(l,0,sizeof(l));
for(int i=1;i<=n;i++){
int x = ss[i]-'a';
if(nxt[p][x]) p = nxt[p][x],ans ++;
else {
for(;p && !nxt[p][x];p=fa[p]);
if(!p) p = 1,ans = 0;
else ans = len[p]+1, p = nxt[p][x];
}
l[p] = max(l[p],ans);
}
for(int i=tot;i;i--){
int x = a[i];
res[x] = min(res[x],l[x]);
if(l[x] && fa[x])
l[fa[x]] = len[fa[x]];//如果它能够匹配到,那么它的fa也应该能匹配到
}
}
inline void Work(){
int ans = 0;
for(int i=1;i<=tot;i++)
ans = max(ans,res[i]);
printf("%d\n",ans);
}
}SAM;
int main(){
scanf("%s",s+1);
int m = strlen(s+1);
for(int i=1;i<=m;i++) SAM.Insert(s[i]-'a');
SAM.Sort(m);
while(~scanf("%s",ss+1)){
int n = strlen(ss+1);
SAM.Solve(n);
}
SAM.Work();
return 0;
}