洛谷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;
}
posted @ 2023-03-03 01:10  quanjun  阅读(16)  评论(0编辑  收藏  举报