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

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

传送门


解析:

小声BB:vjudge上面应该出了一点问题,C++会Language Erro,C++14就没有问题。

思路:

建立其中一个串的SAM,然后拿另外一个串去匹配,能够匹配到的最大长度就是最长公共子串。

啊你问我为什么这样是对的,请回去重新学习什么是有限状态自动机。
能搞明白FSM的应该都不会问这种问题。


代码:

#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;
	point fa,son[26];
	SAM_node():len(0),fa(NULL){}
};

cs int N=250005;
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 int query(char *s,int len){
		re int ans=0,now=0;
		re point u=nd;
		for(int re i=1;i<=len;++i){
			if(u->son[s[i]-'a']){
				u=u->son[s[i]-'a'];
				ans=max(ans,++now);
				continue;
			}
			while(u&&!u->son[s[i]-'a'])u=u->fa;
			ans=max(ans,now=(u?u->len:-1)+1);u=u?u->son[s[i]-'a']:nd;
		}
		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]);
	scanf("%s",s+1);len=strlen(s+1);
	printf("%d",sam.query(s,len));
	return 0;
}

猜你喜欢

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