YC342A [ 20240922 CQYC NOIP 模擬賽 T1 ] 字首(lcp)

cxqghzj發表於2024-10-02

題意

給定 \(n, m\) 以及長為 \(n\) 的字串 \(S\)

你需要構造字串 \(T\) 使得 \(\sum LCP(S, T[i, ..., m])\) 最大。

求出這個最大值。

\(n, m \le 5 \times 10 ^ 3\)

Sol

首先不難發現答案一定可以由若干 \(S\) 的字首拼成。考慮找到最小的無法被拆為字首的子段,顯然這個子段無法產生任何貢獻。

考慮一個 \(\texttt{dp}\),設 \(f_{i, j}\) 表示當前放了前 \(i\) 個位置,放到 \(S\) 的字首 \(j\),的答案。

但是這個東西有一個問題,會算漏很多貢獻,因為前一個字首對後面的字首都是有貢獻的。

因此考慮 \(border\),不難發現事實上新增一個點的貢獻就是她的最大 \(border\) 的貢獻 $ + 1$。

  • \(f_{i, j} \leftarrow f_{i - 1, j - 1} + cnt_{j}\)
  • \(f_{i, nxt_j} \leftarrow f_{i, j}\)

做完了,時間複雜度:\(O(n \times m)\)

Code

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
using namespace std;
#ifdef ONLINE_JUDGE

#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf;

#endif
int read() {
    int p = 0, flg = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') flg = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        p = p * 10 + c - '0';
        c = getchar();
    }
    return p * flg;
}
void write(int x) {
    if (x < 0) {
        x = -x;
        putchar('-');
    }
    if (x > 9) {
        write(x / 10);
    }
    putchar(x % 10 + '0');
}
bool _stmer;

const int N = 5e3 + 5;

array <int, N> s;

namespace Kmp {

array <int, N> isl;

void prefix(int n) {
    for (int i = 2; i <= n; i++) {
        isl[i] = isl[i - 1];
        while (isl[i] && s[i] != s[isl[i] + 1]) isl[i] = isl[isl[i]];
        if (s[i] == s[isl[i] + 1]) isl[i]++;
    }
}

} //namespace Kmp

array <array <int, N>, N> f;
array <int, N> cnt;

bool _edmer;
int main() {
    cerr << (&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n";
    int n = read(), m = read();
    for (int i = 1; i <= n; i++) s[i] = read();
    Kmp::prefix(n);
    for (int i = 1; i <= n; i++)
        cnt[i] = cnt[Kmp::isl[i]] + 1;
    f[0].fill(-2e9), f[0][0] = 0;
    for (int i = 1; i <= m; i++) {
        f[i].fill(-2e9);
        for (int j = n; j; j--) {
            f[i][j] = max(f[i][j], f[i - 1][j - 1] + cnt[j]);
            f[i][Kmp::isl[j]] = max(f[i][Kmp::isl[j]], f[i][j]);
        }
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) ans = max(ans, f[m][i]);
    write(ans), puts("");
    return 0;
}

相關文章