题意: 找出现至少k次的子串的最大长度.
思路:据贪心策略,子串变长答案不会减小,所以可以看做是求k个后缀的LCP.因为要求LCP的最大值,而LCP(suffix(sa[i]),suffix(sa[j]))=min{height[k]}(i<j,k∈[i,j]),显然当这k个后缀在排名上连续的时候可以取得最小值.因为若排名不连续,那么涵盖的取最小值的范围一定会变大,而当取值范围变大最小值只会变小.所以这个贪心是正确的.
二分 + 后缀数组(height数组)

我们知道,后缀(j)和后缀(k)的 最 长 公 共 前 缀 为height[rank[j]+1],

height[rank[j]+2],height[rank[j]+3],…,height[rank[k]]中的最小值(设rank[j]<rank[k])。

那么设k个后缀中rank的min=l,max=r,k个的最长公共前缀就是min(height[l+1->r])

所以k个后缀在rank上一定是连续的。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
int n, m, k, p;
int s[maxn];
int sa[maxn], rak[maxn], tx[maxn], height[maxn], q[maxn];
struct node {
	int x, y, id;
}a[maxn],b[maxn];


void rsort() {
	for (int i = 1; i <= m; i++) {
		tx[i] = 0;
	}
	for (int i = 1; i <= n; i++) {
		tx[a[i].y]++;
	}
	for (int i = 1; i <= m; i++) {
		tx[i] += tx[i - 1];
	}
	for (int i = 1; i <= n; i++) {
		b[tx[a[i].y]--] = a[i];
	}
	for (int i = 1; i <= m; i++) {
		tx[i] = 0;
	}
	for (int i = 1; i <= n; i++) {
		tx[b[i].x]++;
	}
	for (int i = 1; i <= m; i++) {
		tx[i] += tx[i - 1];
	}
	for (int i = n; i >= 1; i--) {
		a[tx[b[i].x]--] = b[i];
	}
}


void solve() {
	rsort();
	p = 0;
	for (int i = 1; i <= n; i++) {
		if (a[i].x != a[i - 1].x || a[i].y != a[i - 1].y) {
			++p;
		}
		rak[a[i].id] = p;
	}
	for (int i = 1; i <= n; i++) {
		a[i].x = rak[i];
		a[i].id = sa[rak[i]] = i;
		a[i].y = 0;
	}
	m = p;
}


void ssort() {
	for (int i = 1; i <= n; i++) {
		a[i].x = a[i].y = s[i];
		a[i].id = i;
		m = max(m, s[i]);
	}
	solve();
	for (int j = 1; j <= n; j <<= 1) {
		for (int i = 1; i + j <= n; i++) {
			a[i].y = a[i + j].x;
		}
		solve();
		if (p == n) {
			break;
		}
	}
}


void get_Height() {
	int k = 0;
	for (int i = 1; i <= n; i++) {
		if (k) {
			k--;
		}
		int j = sa[rak[i] - 1];
		while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) {
			k++;
		}
		height[rak[i]] = k;
	}
}

/* 5 2 1 2 1 2 1 */


int check(int x) {
	int i = 1;
	while (1) {
		for (; i <= n && height[i] < x; i++);
		if (i > n) {
			break;
		}
		int cnt = 1;
		for (; i <= n && height[i] >= x; cnt++, i++);
		if (cnt >= k) {
			return 1;
		}
	}
	return 0;
}

int main() {
	scanf("%d%d", &n, &k);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &s[i]);
	}
	ssort(); get_Height();
	int l = 1, r = n;
	int ans = 0;
	while (l <= r) {
		int mid = (l + r) / 2;
		if (check(mid)) {
			l = mid + 1;
		} else {
			r = mid - 1;
		}
	}
	printf("%d\n", l - 1);
	return 0;
}