您的位置:首页 > 其它

cv3160 最长公共子串(SAM)

2018-01-28 15:50 211 查看
题目链接

分析:

AA串建立一个SAMSAM

用BB串在SAMSAM上匹配

能匹配到的最远结点(到rootroot的距离)就是最长公共子串

如果匹配不上的时候,我们直接通过parentparent跳到ta的“失配”上

tip

虽然SAMSAM的空间是O(n)O(n),但是在开数组的时候是大小要到n∗2n∗2

#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

const int N=100003;
int ch[N<<1][26],fa[N<<1],sz=1,last=1,root=1,dis[N<<1];
char a
,b
;

void insert(int x)
{
int pre=last,now=++sz;
last=now;
dis[now]=dis[pre]+1;
for (;pre&&!ch[pre][x];pre=fa[pre]) ch[pre][x]=now;  //找Parent树上有没有这个结点

if (!pre) fa[now]=root;
else
{
int q=ch[pre][x];   //找了一个祖先
if (dis[q]==dis[pre]+1) fa[now]=q;
else
{
int nows=++sz;
dis[nows]=dis[pre]+1;
memcpy(ch[nows],ch[q],sizeof(ch[nows]));
fa[nows]=fa[q]; fa[now]=fa[q]=nows;
for (;pre&&ch[pre][x]==q;pre=fa[pre]) ch[pre][x]=nows;
}
}
}

void solve()
{
int len=strlen(b+1),ans=0,now=root,tmp=0;
for (int i=1;i<=len;i++)
{
int x=b[i]-'a';
if (ch[now][x]) now=ch[now][x],tmp++;
else
{
while (now&&!ch[now][x]) now=fa[now];
if (!now) now=1,tmp=0;
else {
tmp=dis[now]+1;
now=ch[now][x];
}
}
ans=max(ans,tmp);
}
printf("%d",ans);
}

int main()
{
scanf("%s",a+1);
scanf("%s",b+1);
for (int i=1;i<strlen(a+1);i++) insert(a[i]-'a');
solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: