YC342A [ 20240922 CQYC NOIP 模拟赛 T1 ] 前缀(lcp)

题意

给定 \(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;
}
posted @ 2024-10-02 09:29  cxqghzj  阅读(4)  评论(0编辑  收藏  举报