洛谷P2852 [USACO06DEC]Milk Patterns G 题解 后缀数组height数组的应用
题目链接:https://www.luogu.com.cn/problem/P2852
题目大意:
求数列中出现次数至少为 \(k\) 次的连续子序列的最大长度。
解题思路:
可以转成对 \(height\) 数组求 \(RMQ\)(区间长度为 \(k-1\) 的区间最小值 的 最大值)。用单调队列解决。
示例程序:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
int n, k, w, sa[maxn], rk[maxn], oldrk[maxn<<1], height[maxn];
int s[maxn];
int main() {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) scanf("%d", s+i);
for (int i = 1; i <= n; i++) sa[i] = i, rk[i] = s[i];
for (w = 1; w < n; w <<= 1) {
sort(sa+1, sa+n+1, [](int i, int j) {
return rk[i] == rk[j] ? rk[i + w] < rk[j + w] : rk[i] < rk[j];
});
memcpy(oldrk, rk, sizeof(int)*(n+1));
for (int i = 1, p = 0; i <= n; i++) {
if (oldrk[sa[i]] != oldrk[sa[i-1]] || oldrk[sa[i] + w] != oldrk[sa[i-1] + w])
p++;
rk[sa[i]] = p;
}
}
for (int i = 1, k = 0; i <= n; i++) {
if (!rk[i]) continue;
if (k) k--;
while (s[i + k] == s[sa[rk[i] - 1] + k]) k++;
height[rk[i]] = k;
}
deque<int> que;
int ans = 0;
for (int i = 1; i <= n; i++) {
while (!que.empty() && height[que.back()] >= height[i]) que.pop_back();
if (!que.empty() && que.front() <= i - k + 1) que.pop_front();
que.push_back(i);
if (i >= k) ans = max(ans, height[que.front()]);
}
printf("%d\n", ans);
return 0;
}