洛谷LCS2 - Longest Common Substring II
题目大意
给你一些字符串,求它们的最长公共子串。
字符串个数不超过 10 10 10,每个字符串的长度不超过 100000 100000 100000。
题解
可以先看看LCS - Longest Common Substring。
这题与上面那题类似,只不过要多一些操作。
首先,用第一个字符串建一个 S A M SAM SAM,然后在 S A M SAM SAM上面匹配其他的字符串,匹配的方式见上面这道题。
因为有多个字符串,所以不能只用 n o w now now了。我们用 w [ p ] . m x [ i ] w[p].mx[i] w[p].mx[i]表示在用字符串 i i i来在 S A M SAM SAM上匹配时 S A M SAM SAM的位置 p p p上能够达到的最长的长度。
当然,如果一个点可以被匹配到,则这个点的祖先都可以被匹配到。所以每个点要对其子树取 m a x max max,然后对自己的长度取 m i n min min。这个操作我这边用的是拓扑排序来实现,当然其他方法也可以。文章来源:https://www.toymoban.com/news/detail-522399.html
最后,对于 S A M SAM SAM上的每一个位置 p p p,求这个位置在每个字符串匹配后的最小值,即 w [ p ] . m x [ i ] w[p].mx[i] w[p].mx[i]的最小值,让 a n s ans ans对这个值取 m a x max max。最后的 a n s ans ans即为答案。文章来源地址https://www.toymoban.com/news/detail-522399.html
code
#include<bits/stdc++.h>
using namespace std;
const int N=100000;
int s1,t1,cnt,siz=0,lst=0,ans=0,ct[N*2+5],r[N*2+5];
char s[N+5],t[N+5];
queue<int>q;
struct node{
int len,link,bz,mx[15];
map<char,int>nxt;
}w[N*2+5];
void add(char c){
int cur=++siz;
w[cur].len=w[lst].len+1;
int p;
for(p=lst;p!=-1&&!w[p].nxt.count(c);p=w[p].link)
w[p].nxt[c]=cur;
if(p==-1) w[cur].link=0;
else{
int q=w[p].nxt[c];
if(w[p].len+1==w[q].len) w[cur].link=q;
else{
int cl=++siz;
w[cl].len=w[p].len+1;
w[cl].link=w[q].link;
w[cl].nxt=w[q].nxt;
for(;p!=-1&&w[p].nxt[c]==q;p=w[p].link)
w[p].nxt[c]=cl;
w[q].link=w[cur].link=cl;
}
}
lst=cur;
}
void find(){
int p=0,now=0;
for(int i=1;i<=t1;i++){
char c=t[i];
if(w[p].nxt.count(c)){
p=w[p].nxt[c];++now;
}
else{
for(;p!=-1&&!w[p].nxt.count(c);p=w[p].link);
if(p!=-1){
now=w[p].len+1;
p=w[p].nxt[c];
}
else{
now=0;p=0;
}
}
w[p].mx[cnt]=max(w[p].mx[cnt],now);
}
}
void gt(){
for(int i=1;i<=siz;i++) ++ct[w[i].link];
for(int i=1;i<=siz;i++){
if(!ct[i]) q.push(i);
}
while(!q.empty()){
int u=q.front();q.pop();
r[++r[0]]=u;
--ct[w[u].link];
if(!ct[w[u].link]) q.push(w[u].link);
}
}
void up(int c){
for(int i=1;i<=siz;i++){
int u=r[i];
w[w[u].link].mx[c]=min(max(w[w[u].link].mx[c],w[u].mx[c]),w[w[u].link].len);
}
}
int main()
{
scanf("%s",s+1);
s1=strlen(s+1);
w[0].link=-1;
for(int i=1;i<=s1;i++) add(s[i]);
gt();
while(scanf("%s",t+1)!=EOF){
t1=strlen(t+1);
++cnt;
find();
up(cnt);
}
for(int i=1,now;i<=siz;i++){
now=1e9;
for(int j=1;j<=cnt;j++){
now=min(now,w[i].mx[j]);
}
ans=max(ans,now);
}
printf("%d",ans);
return 0;
}
到了这里,关于LCS2 - Longest Common Substring II的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!