bzoj 1717 [Usaco2006 Dec]Milk Patterns 产奶的模式 后缀数组

题面

题目传送门

解法

比较套路的一道题吧

先求出height数组,二分答案\(mid\)

将后缀分成若干组,每一组满足height≥mid

若某一组的后缀个数≥k,那么答案可行

时间复杂度:\(O(n\ log\ n)\)

代码

#include <bits/stdc++.h>
#define N 1000010
using namespace std;
template <typename node> void read(node &x) {
	x = 0; int f = 1; char c = getchar();
	while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
	while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
int n, k, st[N];
struct SuffixArray {
	int x[N], y[N], sa[N], rnk[N], cnt[N], height[N];
	void build() {
		int m = 0;
		for (int i = 1; i <= n; i++) m = max(m, st[i]);
		for (int i = 1; i <= n; i++) cnt[x[i] = st[i]]++;
		for (int i = 2; i <= m; i++) cnt[i] += cnt[i - 1];
		for (int i = n; i; i--) sa[cnt[x[i]]--] = i;
		for (int k = 1; k <= n; k <<= 1) {
			int num = 0;
			for (int i = n - k + 1; i <= n; i++) y[++num] = i;
			for (int i = 1; i <= n; i++)
				if (sa[i] > k) y[++num] = sa[i] - k;
			for (int i = 1; i <= m; i++) cnt[i] = 0;
			for (int i = 1; i <= n; i++) cnt[x[i]]++;
			for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
			for (int i = n; i; i--) sa[cnt[x[y[i]]]--] = y[i], y[i] = 0;
			swap(x, y); x[sa[1]] = 1, num = 1;
			for (int i = 2; i <= n; i++)
				x[sa[i]] = (y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k]) ? num : ++num;
			if (num == n) break; m = num;
		}
		for (int i = 1; i <= n; i++) rnk[sa[i]] = i;
		int k = 0;
		for (int i = 1; i <= n; i++) {
			if (rnk[i] == 1) continue;
			if (k) k--; int j = sa[rnk[i] - 1];
			while (i + k <= n && j + k <= n && st[i + k] == st[j + k]) k++;
			height[rnk[i]] = k;
		}
	}
	bool check(int mid) {
		int las = 1;
		for (int i = 2; i <= n; i++)
			if (height[i] < mid) {
				if (i - las >= k) return true;
				las = i;
			}
		return (n - las + 1) >= k;
	}
	int solve() {
		int l = 0, r = n, ans = 0;
		while (l <= r) {
			int mid = (l + r) >> 1;
			if (check(mid)) ans = mid, l = mid + 1;
				else r = mid - 1;
		}
		return ans;
	}
} SA;
int main() {
	read(n), read(k);
	for (int i = 1; i <= n; i++) read(st[i]);
	SA.build();
	cout << SA.solve() << "\n";
	return 0;
}

posted @ 2018-08-14 22:23  谜のNOIP  阅读(113)  评论(0编辑  收藏  举报