SPOJ1812 LCS2 POI2000 BZOJ2946 公共串 SAM

题目链接
链接是洛谷有翻译的。

题意:
给定一些字符串,求出它们的最长公共子串。输入至多10行,每行包含不超过100000个的小写字母。

这题似乎和POI2000BZOJ2946是同一道题,于是我就也挂上那个标签了。PS:BZOJ的那个是个权限题。。。

题解:
我们之前做过两个串通过SAM找最长公共子串的,具体请看这里
那么我们考虑多个串的做法,其实多个串是可以从两个串拓展来的。思路上就是我们对第一个串建出SAM,然后其他串与这个串匹配,我们对于当前串,算出每个位置能匹配的最大值,然后对于所有的串,我们要对于每个位置取min,因为最小的才能是公共的。具体的实现的话就是每次拿出一个串,像两个串那样在SAM上跑,跑完之后根据parent树更新一下parent树上的点的答案。然后再对每个位置取min。写的时候对于一个字符串,处理它的时候维护一个每个位置的max,对于所有的串,维护一个每个位置的min。最后答案是所有的min中的max。说起来好像挺绕的,但是其实体会一下还是不难理解的。

代码:

#include <bits/stdc++.h>
using namespace std;

int n,fa[400010],len[400010],rt=1,cnt=1,lst=1,ch[400010][26];
int hed[400010],num,ans,mn[400010],mx[400010];
struct node
{
	int to,next;
}a[800010];
char s[100010];
inline void insert(int x)
{
	int cur=++cnt,pre=lst;
	lst=cur;
	len[cur]=len[pre]+1;
	for(;pre&&!ch[pre][x];pre=fa[pre])
	ch[pre][x]=cur;
	if(!pre)
	fa[cur]=rt;
	else
	{
		int ji=ch[pre][x];
		if(len[ji]==len[pre]+1)
		fa[cur]=ji;
		else
		{
			int gg=++cnt;
			memcpy(ch[gg],ch[ji],sizeof(ch[ji]));
			fa[gg]=fa[ji];
			fa[ji]=fa[cur]=gg;
			len[gg]=len[pre]+1;
			for(;pre&&ch[pre][x]==ji;pre=fa[pre])
			ch[pre][x]=gg;
		}
	}
}
inline void add(int from,int to)
{
	a[++num].to=to;
	a[num].next=hed[from];
	hed[from]=num;
}
inline void dfs(int x)
{
	for(int i=hed[x];i;i=a[i].next)
	{
		int y=a[i].to;
		dfs(y);
		mx[x]=max(mx[x],min(mx[y],len[x]));
	}
}
inline void qwq()
{
	int l=0,cur=rt;
	memset(mx,0,sizeof(mx));
	for(int i=1;i<=n;++i)
	{
		int x=s[i]-'a';
		if(ch[cur][x])
		{
			cur=ch[cur][x];
			++l;
		}
		else
		{
			for(;cur&&!ch[cur][x];cur=fa[cur]);
			if(!cur)
			{
				cur=rt;
				l=0;
			}
			else
			{
				l=len[cur]+1;
				cur=ch[cur][x];
			}
		}
		mx[cur]=max(mx[cur],l);
	}
	dfs(1);
	for(int i=1;i<=cnt;++i)
	mn[i]=min(mn[i],mx[i]);
}
int main()
{
	scanf("%s",s+1);
	n=strlen(s+1);
	for(int i=1;i<=n;++i)
	insert(s[i]-'a');
	for(int i=2;i<=cnt;++i)
	add(fa[i],i);
	memset(mn,0x3f,sizeof(mn));
	while(~scanf("%s",s+1))
	{
		n=strlen(s+1);
		qwq();
	}
	for(int i=1;i<=cnt;++i)
	ans=max(ans,mn[i]);
	printf("%d\n",ans);
	return 0; 
}
Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值