传送门[洛谷]
多个串!1811的升级版~
其实做法很相似 我们只需要对第一个串建立SAM
然后 每个串在上面跑 由于是求所有字符串交的LCS
我们只需要记录每个节点与当前串匹配的max和之前所有串匹配的min
max是需要子树更新的 min要记得和当前的max还有len[节点最大长度]取min
然后这样就做完啦。
(才不会说我读的是所有字符串并的LCS 这个的做法可以直接跑一个然后扔进去一个就可以了qwq)
附代码。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define inf 20021225
#define ll long long
#define mxn 100100
using namespace std;
struct edge{int to,lt;}e[mxn*4];
struct node{int ch[26],fa,len,mx,mn;}t[mxn*4];
int poi,lt,rt,in[mxn*4],cnt,n;char ch[mxn];
void add(int x,int y){e[++cnt].to=y;e[cnt].lt=in[x];in[x]=cnt;}
int id(char c){return c-'a';}
void insert(int c)
{
int p=lt,np=lt=++poi; t[np].len=t[p].len+1;
for(;p&&!t[p].ch[c];p=t[p].fa) t[p].ch[c]=np;
if(!p){t[np].fa=rt;return;}
int q=t[p].ch[c];
if(t[q].len==t[p].len+1){t[np].fa=q;return;}
int nq=++poi; t[nq].len=t[p].len+1;
memcpy(t[nq].ch,t[q].ch,sizeof(t[q].ch));
t[nq].fa=t[q].fa; t[q].fa=t[np].fa=nq;
for(;p&&t[p].ch[c]==q;p=t[p].fa) t[p].ch[c]=nq;
}
void build(){for(int i=2;i<=poi;i++) add(t[i].fa,i);}
void init(){for(int i=1;i<=poi;i++) t[i].mx=0;}
void prework(){for(int i=1;i<=poi;i++) t[i].mn=inf;}
void calc()
{
int pos=rt,cur=0;
for(int i=1;i<=n;i++)
{
int tmp=id(ch[i]);
if(t[pos].ch[tmp]) cur++,pos=t[pos].ch[tmp];
else
{
for(;pos&&!t[pos].ch[tmp];pos=t[pos].fa);
if(!pos) pos=rt,cur=0;
else cur=t[pos].len+1,pos=t[pos].ch[tmp];
}
t[pos].mx=max(t[pos].mx,cur);
}
}
void dfs(int x)
{
for(int i=in[x];i;i=e[i].lt)
{
dfs(e[i].to);
t[x].mx=max(t[x].mx,min(t[x].len,t[e[i].to].mx));
}
t[x].mn=min(t[x].mn,t[x].mx);
}
int ans;
void getans()
{
for(int i=1;i<=poi;i++) ans=max(ans,t[i].mn);
}
int main()
{
//freopen("in.txt","r",stdin);
scanf("%s",ch+1);n=strlen(ch+1);
rt=lt=++poi;
for(int i=1;i<=n;i++) insert(id(ch[i]));
build();prework();
while(~scanf("%s",ch+1))
{
n=strlen(ch+1);
init();calc();dfs(rt);
}
getans();
printf("%d
",ans);
return 0;
}