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;
}
posted @ 2019-03-28 12:50 xunzhen 阅读(...) 评论(...) 编辑 收藏