Luogu2852 [USACO06DEC]牛奶模式

题目蓝链

Description

给定一个字符串,你需要找到一个最长在这个串中至少出现了(k)次的子串

Solution

我们首先对这个串进行后缀排序,那么对于排序后的任意一个区间([l, r]),那么原串中一定有(r - l + 1)个长度为(MIN_{i in (l, r]} {height_i})的相同字串

于是我们就直接把(height)数列扫一边,同时维护一个单调队列,来维护任意相邻的(k - 1)(height)的最小值,答案便是这些最小值中的最大值

Code

#include <bits/stdc++.h>

using namespace std;

#define fst first
#define snd second
#define mp make_pair
#define squ(x) ((LL)(x) * (x))
#define debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef pair<int, int> pii;

template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }

inline int read() {
	int sum = 0, fg = 1; char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') fg = -1;
	for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
	return fg * sum;
}

const int maxn = 2e4 + 10;
const int maxm = 1e6 + 10;

int n, m, k;
int S[maxn], sa[maxn], buc[maxm], rk[maxn], tmp[maxn], height[maxn];

inline void Radix_sort() {
	for (int i = 1; i <= m; i++) buc[i] = 0;
	for (int i = 1; i <= n; i++) ++buc[rk[i]];
	for (int i = 1; i <= m; i++) buc[i] += buc[i - 1];
	for (int i = n; i >= 1; i--) sa[buc[rk[tmp[i]]]--] = tmp[i];
}

inline void get_sa() {
	for (int i = 1; i <= n; i++) rk[i] = S[i] + 1, tmp[i] = i;
	m = 1e6 + 1, Radix_sort();
	for (int k = 1; k <= n; k <<= 1) {
		int p = 0;
		for (int i = n - k + 1; i <= n; i++) tmp[++p] = i;
		for (int i = 1; i <= n; i++) if (sa[i] > k) tmp[++p] = sa[i] - k;
		Radix_sort(), swap(rk, tmp);
		rk[sa[1]] = 1, m = 1;
		for (int i = 2; i <= n; i++)
			rk[sa[i]] = (tmp[sa[i]] == tmp[sa[i - 1]] && tmp[sa[i] + k] == tmp[sa[i - 1] + k]) ? m : ++m;
		if (m >= n) break;
	}
}

inline void get_height() {
	for (int i = 1, k = 0; i <= n; i++) {
		if (k) --k;
		int j = sa[rk[i] - 1];
		while (S[i + k] == S[j + k]) ++k;
		height[rk[i]] = k;
	}
}

int main() {
#ifdef xunzhen
	freopen("milk.in", "r", stdin);
	freopen("milk.out", "w", stdout);
#endif

	n = read(), k = read();
	for (int i = 1; i <= n; i++) S[i] = read();
	get_sa(), get_height();

	deque<int> q;
	int ans = 0;
	for (int i = 2; i <= n; i++) {
		while (!q.empty() && height[q.back()] > height[i]) q.pop_back();
		q.push_back(i);
		while (!q.empty() && q.front() <= i - k + 1) q.pop_front();
		chkmax(ans, height[q.front()]);
	}
	cout << ans << endl;

	return 0;
}
原文地址:https://www.cnblogs.com/xunzhen/p/10614197.html