SP1811-Longest Common Substring【SAM】

正题

题目链接:https://www.luogu.com.cn/problem/SP1811


题目大意

求两个串的最长公共子串。


解题思路

对与第一个串首先构建一个 S A M SAM SAM,然后考虑让第二个串在上面匹配。

对于枚举的每个位置要在 S A M SAM SAM上找一个节点使得它的后缀是枚举到的位置的后缀。所以对于当前节点如果有新加入的字符串的边就走过去,如果没有我们就可以在 p a r e n t parent parent树上往前跳,因为跳到的节点代表的后缀是满足且仅满足这些位置的后缀是加入这个字符之前的后缀,跳了之后取那个节点的 l e n len len就好了。

时间复杂度 O ( n ) O(n) O(n)


c o d e code code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=5e5+10;
int n,las,tot,len[N],fa[N];
char s[N];int ch[N][26],ans;
void add(int c){
	int p=las;int np=las=++tot;
	len[np]=len[p]+1;
	for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
	if(!p)fa[np]=1;
	else{
		int q=ch[p][c];
		if(len[p]+1==len[q])fa[np]=q;
		else{
			int nq=++tot;len[nq]=len[p]+1;
			memcpy(ch[nq],ch[q],sizeof(ch[q]));
			fa[nq]=fa[q];fa[q]=fa[np]=nq;
			for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;
		}
	}
	return;
}
int main()
{
	las=tot=1;
	scanf("%s",s+1);n=strlen(s+1);
	for(int i=1;i<=n;i++)
		add(s[i]-'a');
	memset(s,0,sizeof(s));
	scanf("%s",s+1);n=strlen(s+1);
	int now=1,L=0;
	for(int i=1;i<=n;i++){
		int c=s[i]-'a';
		if(ch[now][c])now=ch[now][c],++L;
		else{
			for(;now&&!ch[now][c];now=fa[now]);
			if(now)L=len[now]+1,now=ch[now][c];
			else L=0,now=1;
		}
		ans=max(ans,L);
	}
	printf("%d",ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值