●SPOJ 1811 Longest Common Substring

题链:

http://poj.org/problem?id=2774

题解:

求两个字符串(S,T)的最长公共子串。
对 S串建后缀自动机。
接下来就用这个自动机去求出能和 S串匹配的 T的每一个前缀的最长的后缀。
最终答案就是对每个 T的前缀得到的答案取最大值就好了。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 250050
#define filein(x) freopen(#x".in","r",stdin);
#define fileout(x) freopen(#x".out","w",stdout);
using namespace std;
struct SAM{
	int size,last,q,p,nq,np;
	int pre[MAXN*2],step[MAXN*2],ch[MAXN*2][26];
	int Newnode(int a,int b){
		step[size]=a; memcpy(ch[size],ch[b],sizeof(ch[b]));
		return size++;
	}
	void Extend(int x){
		p=last; last=np=Newnode(step[p]+1,0);
		while(p&&!ch[p][x]) ch[p][x]=np,p=pre[p];
		if(!p) pre[np]=1;
		else{
			q=ch[p][x];
			if(step[q]!=step[p]+1){
				nq=Newnode(step[p]+1,q);
				pre[nq]=pre[q]; pre[q]=pre[np]=nq;
				while(p&&ch[p][x]==q) ch[p][x]=nq,p=pre[p];
			}
			else pre[np]=q;
		}
	}
	void Build(char *S){
		memset(ch[0],0,sizeof(ch[0]));
		size=1; last=Newnode(0,0); pre[last]=0;
		for(int i=0;S[i];i++) Extend(S[i]-‘a‘);
	}
	int Match(char *T){
		p=1; int ans=0;
		for(int j=0,x,match=0;T[j];j++){ //与 T的每个前缀匹配
			x=T[j]-‘a‘;
			if(ch[p][x]) match++,p=ch[p][x];
			else{
				while(p&&!ch[p][x]) p=pre[p];
				if(!p) match=0,p=1;
				else match=step[p]+1,p=ch[p][x];
			}
			ans=max(ans,match);
		}
		return ans;
	}
}suf;
char S[MAXN],T[MAXN];
int main()
{
	scanf(" %s %s",S,T);
	suf.Build(S);
	printf("%d",suf.Match(T));
	return 0;
}
时间: 2024-10-18 20:17:35

●SPOJ 1811 Longest Common Substring的相关文章

SPOJ 1811 Longest Common Substring(求两个串的最长公共子串)

http://www.spoj.com/problems/LCS/ 题目:求两个串的最长公共子串 分析: 以A建立SAM 让B在SAM上匹配可以类比于kmp思想,我们知道在Parent树上,fa是当前节点的子集,也就是说满足最大前缀,利用这个就可以做题了 #include <bits/stdc++.h> #define LL long long #define P pair<int, int> #define lowbit(x) (x & -x) #define mem(a

SPOJ 1811 Longest Common Substring

Description 给出两个字符串,求最长公共子串. Sol SAM. 这题随便做啊...后缀数组/Hash+二分都可以. SAM就是模板啊...直接在SAM上跑就行,没有了 \(go[w]\) 就往 \(par\) 跳. 每走一步统计一下答案. Code #include<cstdio> #include<cstring> #include<iostream> using namespace std; const int N = 250005; struct St

SPOJ 1811LCS Longest Common Substring

后缀自动机裸题.... Longest Common Substring Time Limit: 2000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu [Submit]   [Go Back]   [Status] Description A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is

【SPOJ】Longest Common Substring II (后缀自动机)

[SPOJ]Longest Common Substring II (后缀自动机) 题面 Vjudge 题意:求若干个串的最长公共子串 题解 对于某一个串构建\(SAM\) 每个串依次进行匹配 同时记录\(f[i]\)表示走到了\(i\)节点 能够匹配上的最长公共子串的长度 当然,每个串的\(f[i]\)可以更新\(f[i.parent]\) 所以需要拓扑排序 对于每个串求出每个节点的最长匹配 然后对他们取\(min\),表示某个节点大家都能匹配的最长长度 最后对于所有点的值都取个\(max\)

【SPOJ】Longest Common Substring(后缀自动机)

[SPOJ]Longest Common Substring(后缀自动机) 题面 Vjudge 题意:求两个串的最长公共子串 题解 \(SA\)的做法很简单 不再赘述 对于一个串构建\(SAM\) 另外一个串在\(SAM\)上不断匹配 最后计算答案就好了 匹配方法: 如果\(trans(s,c)\)存在 直接沿着\(trans\)走就行,同时\(cnt++\) 否则沿着\(parent\)往上跳 如果存在\(trans(now,c),cnt=now.longest+1\) 否则,如果不存在可行的

【SPOJ】Longest Common Substring

[SPOJ]Longest Common Substring 求两个字符串的最长公共子串 对一个串建好后缀自动机然后暴力跑一下 废话 讲一下怎么跑吧 从第一个字符开始遍历,遍历不到了再沿着\(parents\)走看能否找到出路,走到某个点时,统计一下走过了多少点然后更新答案 来说说这样做的正确性: 遍历是肯定的, PAM 从根节点出发的任意路径都表示一个子串 沿着\(parents\)边往后走,保证贪心情况下维护最长公共子串寻找出路 注意这里是统计走过了多少点更新答案,不能直接通过\(len\)

【SPOJ】Longest Common Substring II

[SPOJ]Longest Common Substring II 多个字符串求最长公共子串 还是将一个子串建SAM,其他字符串全部跑一边,记录每个点的最大贡献 由于是所有串,要对每个点每个字符串跑完后去最小值才是每个点的最终贡献 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm

后缀自动机(SAM) :SPOJ LCS - Longest Common Substring

LCS - Longest Common Substring no tags A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the set of lowercase letters. Substring, also called factor, is a consecutive sequence of characters occurrences at

Spoj LCS2 - Longest Common Substring II

题目描述 A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the set of lowercase letters. Substring, also called factor, is a consecutive sequence of characters occurrences at least once in a string. Now your t