HihoCoder - 1415 后缀数组三·重复旋律3

时间限制:5000ms
单点时限:1000ms
内存限制:256MB

描述

小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为长度为 N 的数构成的数列。小Hi在练习过很多曲子以后发现很多作品中的旋律有共同的部分。

旋律是一段连续的数列,如果同一段旋律在作品A和作品B中同时出现过,这段旋律就是A和B共同的部分,比如在abab 在 bababab 和 cabacababc 中都出现过。小Hi想知道两部作品的共同旋律最长是多少?

解题方法提示

输入

共两行。一行一个仅包含小写字母的字符串。字符串长度不超过 100000。

输出

一行一个整数,表示答案。

样例输入

abcdefg

abacabca

样例输出

3

总结:后缀数组

将两个输入的字符串拼在一起,中间加上一个没有出现过的特殊字符如‘#’

然后构造出sa, rk, height数组

判断sa[i]与sa[i - 1]是否是分列于特殊字符的两列,是的话就ans = max(ans, height[i]) 更新答案便是

#include <bits/stdc++.h>

using namespace std;
const int maxn = 1e5 + 7;
int sa[maxn], rk[maxn], c[maxn], y[maxn], k, p, ln;
int H[maxn], wr[maxn], m, n; char a[maxn * 2], b[maxn];

void SA(int x) {
	m = x;
	for (int i = 1; i <= n; ++i) rk[i] = a[i];
	for (int i = 1; i <= n; ++i) c[rk[i]]++;
	for (int i = 1; i <= m; ++i) c[i] += c[i - 1];
	for (int i = n; i >= 1; --i) sa[c[rk[i]]--] = i;
	p = 0; ln = 1;
	while(p < n) {
		k = 0;
		for (int i = n - ln + 1; i <= n; ++i) y[++k] = i;
		for (int i = 1; i <= n; ++i) if(sa[i] > ln) y[++k] = sa[i] - ln;
		memset(c, 0, sizeof c);
		for (int i = 1; i <= n; ++i) wr[i] = rk[i];
		for (int i = 1; i <= n; ++i) c[wr[y[i]]]++;
		for (int i = 1; i <= m; ++i) c[i] += c[i - 1];
		for (int i = n; i >= 1; --i) sa[c[wr[y[i]]]--] = y[i];
		for (int i = 1; i <= n; ++i) wr[i] = rk[i];
		p = 1; rk[sa[1]] = 1;
		for (int i = 2; i <= n; ++i) {
			if(!(wr[sa[i]] == wr[sa[i - 1]] && wr[sa[i] + ln] == wr[sa[i - 1] + ln])) ++p;
			rk[sa[i]] = p;
		} m = p; ln <<= 1;
	}
}
void GH() {
	k = 0;
	for (int i = 1; i <= n; ++i) rk[sa[i]] = i;
	for (int i = 1; i <= n; ++i) {
		if(k) --k; int j = sa[rk[i] - 1];
		while(a[i + k] == a[j + k]) ++k;
		H[rk[i]] = k;
	} 
}
int main() {
	scanf("%s", a + 1); n = strlen(a + 1);
	scanf("%s", b + 1); a[++n] = '#'; int h = strlen(b + 1);
	int k = n;
	for (int i = 1; i <= h; ++i) a[++n] = b[i];
	SA(256); GH(); int ans = 0;
	for (int i = 2; i <= n; ++i) {
		if(((sa[i - 1] <= k) && (sa[i] > k)) || ((sa[i - 1] > k) && (sa[i] <= k))) 
		ans = max(ans, H[i]);
	} printf("%d\n", ans);
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/oi-forever/p/9154897.html