SPOJ1812 Longest Common Substring II
Posted autoint
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPOJ1812 Longest Common Substring II相关的知识,希望对你有一定的参考价值。
题意
A string is finite sequence of characters over a non-empty finite set Σ.
In this problem, Σ is the set of lowercase letters.
Substring, also called factor, is a consecutive sequence of characters occurrences at least once in a string.
Now your task is a bit harder, for some given strings, find the length of the longest common substring of them.
Here common substring means a substring of two or more strings.
给定n个串,求它们的最长公共子串。
at most 10 lines,no more than 100000
分析
参照iwt的题解。
本题容易看出就是分别将所有串的所有匹配长度记录在状态上,然后取所有串记录值的min,后再对所有状态取max。
但是不要忘记了一点:更新parent树的祖先。
为什么呢?首先如果子树被匹配过了,那么长度一定大于任意祖先匹配的长度(甚至有些祖先匹配长度为0!为什么呢,因为我们在匹配的过程中,只是找到一个子串,可能还遗漏了祖先没有匹配到,这样导致了祖先的记录值为0,那么在对对应状态取min的时候会取到0,这样就wa了。而且注意,如果匹配到了当前节点,那么祖先们一定都可以赋值为祖先的length!因为当前节点的length大于任意祖先。(
比如数据
acbbc
bc
ac
答案应该是1没错吧。如果没有更新祖先,那么答案会成0。
这个多想想就行了。
所以以后记住:对任意多串匹配时,凡是对同一个状态取值时,要注意当前状态的子树是否比当前状态记录的值优。
时间复杂度:线性。
代码
#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<typename T>il T read()
{
rg T data=0,w=1;
rg char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') w=-1;
ch=getchar();
}
while(isdigit(ch))
{
data=data*10+ch-'0';
ch=getchar();
}
return data*w;
}
template<typename T>il T read(rg T&x)
{
return x=read<T>();
}
typedef long long ll;
co int N=2e5;
namespace SAM
{
int tot,last;
int ch[N][26],fail[N]={-1},len[N];
void extend(int k)
{
int cur=++tot;
len[cur]=len[last]+1;
int p=last;
while(~p&&!ch[p][k])
{
ch[p][k]=cur;
p=fail[p];
}
if(p==-1)
fail[cur]=0;
else
{
int q=ch[p][k];
if(len[q]==len[p]+1)
fail[cur]=q;
else
{
int clone=++tot;
std::copy(ch[q],ch[q]+26,ch[clone]);
fail[clone]=fail[q],len[clone]=len[p]+1;
while(~p&&ch[p][k]==q)
{
ch[p][k]=clone;
p=fail[p];
}
fail[cur]=fail[q]=clone;
}
}
last=cur;
}
int c[N],id[N],mx[N],arr[N];
void build(char s[],int n)
{
for(int i=0;i<n;++i)
extend(s[i]-'a');
for(int i=0;i<=tot;++i)
++c[len[i]];
for(int i=1;i<=n;++i)
c[i]+=c[i-1];
for(int i=0;i<=tot;++i)
id[--c[len[i]]]=i; // edit 1:--c for 0
std::copy(len,len+tot+1,mx);
}
void find(char s[],int n)
{
int p=0,l=0;
for(int i=0;i<n;++i)
{
int k=s[i]-'a';
if(ch[p][k])
p=ch[p][k],++l;
else
{
while(~p&&!ch[p][k])
p=fail[p];
if(p==-1)
p=l=0;
else
l=len[p]+1,p=ch[p][k];
}
arr[p]=std::max(arr[p],l);
}
for(int i=tot;i>=0;--i)
{
int p=id[i];
mx[p]=std::min(mx[p],arr[p]);
if(arr[p]&&fail[p])
arr[fail[p]]=len[fail[p]];
arr[p]=0;
}
}
int getans()
{
int ans=0;
for(int i=0;i<=tot;++i)
ans=std::max(ans,mx[i]);
return ans;
}
}
char buf[N];
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
scanf("%s",buf);
SAM::build(buf,strlen(buf));
while(~scanf("%s",buf))
SAM::find(buf,strlen(buf));
printf("%d
",SAM::getans());
return 0;
}
以上是关于SPOJ1812 Longest Common Substring II的主要内容,如果未能解决你的问题,请参考以下文章
[SPOJ1812]Longest Common Substring II
SPOJ1812 Longest Common Substring II
spoj1812 LCS2 - Longest Common Substring II
刷题SPOJ 1812 LCS2 - Longest Common Substring II