2018.12.15【SPOJ-LCS2】Longest Common Substring II(后缀自动机SAM)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/85015720

传送门


解析:

这道题可以把所有串接在一起构建后缀自动机来做,但是那样还不如写后缀数组。。。

所以这里提供一个只有后缀自动机能实现的做法。

思路:

首先构建出第一个串的后缀自动机。

然后拿其他的串放到后缀自动机上面跑。同时更新答案。

代码里面的 l l 记录的是该串在该状态下能够与前面所有串产生的最大交集, l e n len 记录的是前面所有串在该状态下能够产生的最大交集。

跑的时候记录一下目前匹配了的最长长度,根据下一个状态分别处理。

1.当前状态已经具有字符 c c 的转移
直接进入下一个状态,当前匹配长度+1,更新下一个状态的交集大小。

接下来的过程有点像构建后缀自动机时候的做法。
2.否则,我们向上跳fail,直到彻底失配或者遇到一个具有字符 c c 转移的状态。
(1)如果彻底失配,清空当前匹配长度,
(2)否则,匹配长度为当前状态 l e n + 1 len+1 ,因为我们马上就有下一个 c c 能够多匹配一位。进入下一个状态。

一次状态更新完成后,我们都需要对它fail链上面的状态全部更新,因为他们全部能够完成匹配。其实就是所有后缀的状态更新一遍。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

typedef struct SAM_node *point;
struct SAM_node{
	int len,l;
	point fa,son[26];
	SAM_node():fa(NULL),len(0){}
};

cs int N=100005;
struct SAM{
	SAM_node nd[N<<1];
	point now,last;
	SAM():now(nd),last(nd){}
	
	inline void push_back(char c){
		c-='a';
		point cur=++now;
		cur->len=last->len+1;
		point p=last;
		for(;p&&!p->son[c];p=p->fa)p->son[c]=cur;
		if(!p)cur->fa=nd;
		else if(p->son[c]->len==p->len+1)cur->fa=p->son[c];
		else {
			point clone=++now,q=p->son[c];
			*clone=*q;
			clone->len=p->len+1;
			q->fa=cur->fa=clone;
			for(;p&&p->son[c]==q;p=p->fa)p->son[c]=clone;
		}
		last=cur;
	}
	
	inline void make_LCS(char *s,int len){
		re point u=nd;re int nowl=0;
		for(int re i=1;i<=len;++i){
			re int c=s[i]-'a';
			if(u->son[c]){
				u=u->son[c];
				u->l=max(u->l,min(u->len,++nowl));
			}
			else{
				for(;u&&!u->son[c];u=u->fa);
				if(!u)u=nd,nowl=0;
				else {
					nowl=u->len+1;
					u=u->son[c];
					u->l=max(u->l,min(u->len,nowl));
				}
			}
			for(point re p=u->fa;p&&p->l!=p->len;p=p->fa)p->l=p->len;
		}
		for(u=nd;u<=now;++u)u->len=u->l,u->l=0;
	}
	
	inline int query(){
		int ans=0;
		for(point re p=nd;p<=now;++p)ans=max(ans,p->len);
		return ans;
	}
}sam;

char s[N];int len;
signed main(){
	scanf("%s",s+1);len=strlen(s+1);
	for(int re i=1;i<=len;++i)sam.push_back(s[i]);
	while(~scanf("%s",s+1)){
		len=strlen(s+1);
		sam.make_LCS(s,len);
	}
	printf("%d",sam.query());
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/85015720