[POJ 2774] Long Long Message 【后缀数组】

题目链接:POJ - 2774

题目分析

题目要求求出两个字符串的最长公共子串,使用后缀数组求解会十分容易。

将两个字符串用特殊字符隔开再连接到一起,求出后缀数组。

可以看出,最长公共子串就是两个字符串分别的一个后缀的 LCP ,并且这两个后缀在 SA 中一定是相邻的。

那么他们的 LCP 就是 Height[i] ,当然,Height[i] 的最大值不一定就是 LCS ,因为可能 SA[i] 和 SA[i-1] 是在同一个字符串中。

那么判断一下,如果 SA[i] 与 SA[i - 1] 分别在两个字符串中,就用 Height[i] 更新 Ans 。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

const int MaxL = 200000 + 15;

int n, l1, l2, Ans;
int A[MaxL], Rank[MaxL], Height[MaxL], SA[MaxL];
int VA[MaxL], VB[MaxL], VC[MaxL], Sum[MaxL];

char S1[MaxL], S2[MaxL];

inline bool Cmp(int *a, int x, int y, int l) {
	return (a[x] == a[y]) && (a[x + l] == a[y + l]);
}

void DA(int *A, int n, int m) {
	int *x, *y, *t;
	x = VA; y = VB;
	for (int i = 1; i <= m; ++i) Sum[i] = 0;
	for (int i = 1; i <= n; ++i) ++Sum[x[i] = A[i]];
	for (int i = 2; i <= m; ++i) Sum[i] += Sum[i - 1];
	for (int i = n; i >= 1; --i) SA[Sum[x[i]]--] = i;
	int p, q;
	p = 0;
	for (int j = 1; p < n; j <<= 1, m = p) {
		q = 0;
		for (int i = n - j + 1; i <= n; ++i) y[++q] = i;
		for (int i = 1; i <= n; ++i) {
			if (SA[i] <= j) continue;
			y[++q] = SA[i] - j;
		}
		for (int i = 1; i <= n; ++i) VC[i] = x[y[i]];
		for (int i = 1; i <= m; ++i) Sum[i] = 0;
		for (int i = 1; i <= n; ++i) ++Sum[VC[i]];
		for (int i = 2; i <= m; ++i) Sum[i] += Sum[i - 1];
		for (int i = n; i >= 1; --i) SA[Sum[VC[i]]--] = y[i];
		t = x; x = y; y = t;
		x[SA[1]] = 1; p = 1;
		for (int i = 2; i <= n; ++i)
			x[SA[i]] = Cmp(y, SA[i], SA[i - 1], j) ? p : ++p;
	}
	for (int i = 1; i <= n; ++i) Rank[SA[i]] = i;

	//GetHeight
	int h, o;
	h = 0;
	for (int i = 1; i <= n; ++i) {
		if (Rank[i] == 1) continue;
		o = SA[Rank[i] - 1];
		while (A[i + h] == A[o + h]) ++h;
		Height[Rank[i]] = h;
		if (h > 0) --h;
	}
}

int main()
{
	scanf("%s%s", S1 + 1, S2 + 1);
	l1 = strlen(S1 + 1);
	l2 = strlen(S2 + 1);
	for (int i = 1; i <= l1; ++i)
		A[i] = S1[i] - ‘a‘ + 1;
	A[l1 + 1] = 27;
	for (int i = 1; i <= l2; ++i)
		A[l1 + 1 + i] = S2[i] - ‘a‘ + 1;
	A[l1 + 1 + l2 + 1] = 28;
	n = l1 + 1 + l2 + 1;
	DA(A, n, 28);
	Ans = 0;
	for (int i = 2; i <= n - 1; ++i) {
		if (Height[i] > Ans) {
			if (SA[i] <= l1 && SA[i - 1] > l1 + 1) Ans = Height[i];
			if (SA[i] > l1 + 1 && SA[i - 1] <= l1) Ans = Height[i];
		}
	}
	printf("%d\n", Ans);
	return 0;
}

  

时间: 2024-08-28 00:23:24

[POJ 2774] Long Long Message 【后缀数组】的相关文章

poj 2774 Long Long Message(后缀数组入门题)

1 /****************************************************************** 2 题目: Long Long Message(poj 2774) 3 链接: http://poj.org/problem?id=2774 4 题意: 给两个字符串,找最长的公共子串 5 算法: 后缀数组 6 算法思想: 后缀数组就是套模板求先应得数组,这题用到了两个数组,分 7 别是sa[],height[];sa[i]表示所有后缀按字典数排序后以s[i

poj 2774 Long Long Message 后缀数组基础题

Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 24756   Accepted: 10130 Case Time Limit: 1000MS Description The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes to him these days: his mother is ge

poj 2774 Long Long Message 后缀数组LCP理解

题目链接 题意:给两个长度不超过1e5的字符串,问两个字符串的连续公共子串最大长度为多少? 思路:两个字符串连接之后直接后缀数组+LCP,在height中找出max同时满足一左一右即可: #include<iostream> #include<cstdio> #include<cstring> #include<string.h> #include<algorithm> #include<map> #include<queue&

poj 2774 Long Long Message 后缀数组

点击打开链接题目链接 Long Long Message Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 23327   Accepted: 9566 Case Time Limit: 1000MS Description The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes to him

POJ 2774 Long Long Message ——后缀数组

[题目分析] 用height数组RMQ的性质去求最长的公共子串. 要求sa[i]和sa[i-1]必须在两个串中,然后取height的MAX. 利用中间的字符来连接两个字符串的思想很巧妙,记得最后还需要空一个位置避免冲突. [代码] #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set>

PKU 2774 Long Long Message (后缀数组练习模板题)

题意:给你两个字符串,求最长公共字串的长度. by:罗穗骞模板 #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define M 303 #define inf 0x3fffffff #define maxn 500000 #define ws ww #define rank RANK #define F

POJ 2774 Long Long Message (最长公共子串)

Long Long Message Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 27062   Accepted: 11010 Case Time Limit: 1000MS Description The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes to him these days

POJ 1743 Musical Theme (后缀数组)

题目大意: 刚才上88个键弹出来的音符. 如果出现重复的,或者是高一个音阶的重复的都算. 思路分析: 具体可以参考训练指南222. height数组表示按照排序后的sa最近的两个后缀的最长前缀. 将height 分块.然后二分答案,二分答案之后去判断是否满足. 要考虑到不重合,还有大于5. 所以二分的时候要从5开始,然后判断的时候要加一个 up - down >len #include <cstdio> #include <iostream> #include <alg

HUID 5558 Alice&#39;s Classified Message 后缀数组+单调栈+二分

http://acm.hdu.edu.cn/showproblem.php?pid=5558 对于每个后缀suffix(i),想要在前面i - 1个suffix中找到一个pos,使得LCP最大.这样做O(n^2) 考虑到对于每一个suffix(i),最长的LCP肯定在和他排名相近的地方取得. 按排名大小顺序枚举位置,按位置维护一个递增的单调栈,对于每一个进栈的元素,要算一算栈内元素和他的LCP最大是多少. 如果不需要输出最小的下标,最大的直接是LCP(suffix(st[top]),  suff

POJ 3729 Facer’s string (后缀数组)

题目大意: 串1中有多少个后缀和 串2中的某个后缀 的lcp 为 k 思路分析: 先找出 长度至少为k的对数有多少. 再找出 至少为k+1的有多少 然后相减. #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <map> #include <string> #define maxn 110005 using na