code vs 3160 最长公共子串(后缀自动机)

题目描述 Description

给出两个由小写字母组成的字符串,求它们的最长公共子串的长度。

输入描述 Input Description

读入两个字符串

输出描述 Output Description

输出最长公共子串的长度

样例输入 Sample Input
yeshowmuchiloveyoumydearmotherreallyicannotbelieveit
yeaphowmuchiloveyoumydearmother
样例输出 Sample Output

27

数据范围及提示 Data Size & Hint

单个字符串的长度不超过100000


题解:后缀自动机。

对其中的一个串建立后缀自动机,然后用另一个串在自动机上匹配。类似在AC自动机上的匹配过程,匹配不上了跳转到parent指针(指的是记录的是上一个可以接收后缀的结点(如果当前结点可以接收新的后缀,那么parent指向的结点也一定可以接收后缀)),然后进行匹配。另外l[i]记录的是从根节点到当前节点的最长距离。

匹配上的最长的长度即为最长公共子串。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 200003
using namespace std;
int n,m,ch[N][30],fa[N],a[N],l[N],np,nq,p,q,last,cnt,root;
char s[N],s1[N];
void extend(int x)
{
	int c=a[x];
	p=last; np=++cnt; last=np;
	l[np]=x;
	for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
	if (!p) fa[np]=root;
	else {
		int q=ch[p][c];
		if (l[p]+1==l[q]) fa[np]=q;
		else {
			int nq=++cnt; l[nq]=l[p]+1;
			memcpy(ch[nq],ch[q],sizeof ch[nq]);
			fa[nq]=fa[q];
			fa[np]=fa[q]=nq;
			for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq; 
		}
	}
}
int solve()
{
	int tmp=0,ans=0; 
	for (int i=1;i<=m;i++) {
		int c=s1[i]-'a';
		if (ch[p][c]) p=ch[p][c],tmp++;
		else {
			while (p&&!ch[p][c]) p=fa[p];
			if (!p) p=1,tmp=0;
			else {
				tmp=l[p]+1;
				p=ch[p][c];
			}
		}
		ans=max(ans,tmp);
	}
	return ans;
}
int main()
{
	freopen("a.in","r",stdin);
	scanf("%s",s+1);
	n=strlen(s+1); last=root=++cnt;
	for (int i=1;i<=n;i++) a[i]=s[i]-'a';
	for (int i=1;i<=n;i++) extend(i);
	scanf("%s",s1+1);
	m=strlen(s1+1);
	printf("%d",solve());
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值