最长公共子串 后缀自动机

【题目描述】

给定两个字符串A和B,求它们的最长公共子串

【分析】

我们考虑将A串建成后缀自动机

令当前状态为s,同时最大匹配长度为len

我们读入字符x。如果s有标号为x的边, 那么s=trans(s,x),len = len+1

否则我们找到s的第一个祖先a,它有标号为x的边,令 s=trans(a,x),len=Max(a)+1。

如果没有这样的祖先,那么令s=root,len=0。

在过程中更新状态的最大匹配长度

注意到我们求的是对于任意一个Right集合中的r,最大的匹配长度。那么对于一个状态s,它的结果自然也可以作为它Parent的结果,我们可以从底到上更新一遍。

然后问题就解决了。

———来自陈立杰《后缀自动机讲稿》

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;
#define FILE "read"
#define MAXN 200010
#define up(i,j,n) for(int i=j;i<=n;++i)
#define dn(i,j,n) for(int i=j;i>=n;--i)
#define cmax(a,b) a=max(a,b)
#define cmin(a,b) a=min(a,b)
char ch[MAXN];
int n,cnt(1),now(1),len,ans,mx[MAXN],par[MAXN],son[MAXN][27];
void insert(int x){
	int p=now,np=++cnt;
	mx[np]=mx[now]+1;  now=np;
	while(p&&!son[p][x]) son[p][x]=np,p=par[p];
	if(!p) par[np]=1;
	else{
		int q=son[p][x];
		if(mx[q]==mx[p]+1) par[np]=q;
		else{
			int nq=++cnt;
			mx[nq]=mx[p]+1;
			memcpy(son[nq],son[q],sizeof(son[q]));
			par[nq]=par[q];
			par[q]=par[np]=nq;
			while(p&&son[p][x]==q)son[p][x]=nq,p=par[p];
		}
	}
}
int walk(int x){
	while(!son[now][x]&&par[now]){
		now=par[now];
		len=mx[now];
	}
	if(!son[now][x]) return 0;
	now=son[now][x];  len++;
	return len;
}
int main(){
	freopen(FILE".in","r",stdin);
	freopen(FILE".out","w",stdout);
	scanf("%s",ch+1);  n=strlen(ch+1);
	up(i,1,n)  insert(ch[i]-'a');
	scanf("%s",ch+1);  n=strlen(ch+1);  now=1;
	up(i,1,n)  cmax(ans,walk(ch[i]-'a'));
	printf("%d\n",ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值