「解题报告」CF356E Xenia and String Problem

发布时间 2023-06-12 11:16:28作者: APJifengc

比较简单的题。

发现方案很少,考虑对每种方案维护出权值。首先容易得出,好串的长度一定是 \(2^i - 1\) 形式的,这也告诉我们好串的数量上界是 \(O(n \log n)\) 的,那么我们可以对每一个串考虑怎样修改会使得它变成好串。

首先长度为 \(1\) 的一定是好串,直接累计上。

我们分几种情况考虑:

  1. 这个串的左串与右串均为好串且相等:那么只需要中点的字符出现过 \(1\) 次即可,直接枚举 \(26\) 种情况。如果这个串本来就是好串,那么修改除了这个串以外的任何字符也都是合法的。
  2. 这个串的左串与右串均为好串且不相等:那么我们必须修改在左串或者是右串才可能使得两者相等。容易发现如果两个串除了中点之外还有不相等的位置,就一定不可能成为好串,因为这些字符一定至少出现两次。那么就只有可能是两个中点不相等了,将其中一个修改成另外一个能够使它变成好串。还要注意整个串的中点出现一次的限制。
  3. 这个串的左串与右串仅有一个为好串,两串不相等:看看两个串差几个字符,如果仅有一个字符,那么把这个字符改掉即可变成好串,否则一定不可能成为好串。还是要注意中点出现次数。

容易发现只有这三种情况,那么直接对应的去做即可。可以用差分维护答案,复杂度 \(O(n |\Sigma| \log n + n \log^2 n)\)

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005, MAXM = MAXN * 26;
int id(int i, int c) { return 26 * (i - 1) + c + 1; }
const __uint128_t B = 131, P = 0xffffffff00000001;
__uint128_t BASE[MAXN], hs[MAXN];
__uint128_t piece(int l, int r) {
    return (hs[r] - hs[l - 1] * BASE[r - l + 1] % P + P) % P;
}
int n;
char s[MAXN];
long long ans[MAXM];
int f[MAXN][20];
int lcp(int x, int y, int a, int b) {
    int l = 0, r = y - x + 1;
    while (l < r) {
        int mid = (l + r + 1) >> 1;
        if (piece(x, x + mid - 1) == piece(a, a + mid - 1)) l = mid;
        else r = mid - 1;
    }
    return l;
}
void add(int l, int r, long long v) {
    ans[l] += v, ans[r + 1] -= v;
}
int main() {
    scanf("%s", s + 1);
    n = strlen(s + 1);
    BASE[0] = 1;
    for (int i = 1; i <= n; i++) BASE[i] = BASE[i - 1] * B % P;
    for (int i = 1; i <= n; i++) hs[i] = (hs[i - 1] * B + s[i] - 'a' + 1) % P;
    memset(f, -1, sizeof f);
    for (int i = 1; i <= n; i++) f[i][1] = 1 << (s[i] - 'a');
    long long fans = n;
    for (int j = 2; j <= 18; j++) {
        int len = (1 << j) - 1;
        for (int i = 1; i + len - 1 <= n; i++) {
            if (f[i][j - 1] != -1 && f[i + len / 2 + 1][j - 1] != -1
                 && piece(i, i + len / 2 - 1) == piece(i + len / 2 + 1, i + len - 1)) {
                int S = f[i][j - 1] | f[i + len / 2 + 1][j - 1];
                if (!(S >> (s[i + len / 2] - 'a') & 1)) {
                    f[i][j] = S | (1 << (s[i + len / 2] - 'a'));
                    fans += 1ll * len * len;
                }
            }
        }
    }
    ans[1] = n;
    for (int j = 2; j <= 18; j++) {
        int len = (1 << j) - 1;
        for (int l = 1; l + len - 1 <= n; l++) {
            int r = l + len - 1, mid = l + len / 2;
            if (f[l][j] != -1) {
                add(id(1, 0), id(l - 1, 25), 1ll * len * len);
                add(id(r + 1, 0), id(n, 25), 1ll * len * len);
            }
            if (f[l][j - 1] != -1 && f[mid + 1][j - 1] != -1) {
                if (piece(l, mid - 1) == piece(mid + 1, r)) {
                    int S = f[l][j - 1] | f[mid + 1][j - 1];
                    for (int k = 0; k < 26; k++) if (!(S >> k & 1)) {
                        add(id(mid, k), id(mid, k), 1ll * len * len);
                    }
                } else if (lcp(l, mid - 1, mid + 1, r) == len / 4) {
                    if (j > 2) {
                        int S = f[l][j - 2] | f[mid + 1][j - 2];
                        if (S >> (s[mid] - 'a') & 1) continue;
                    }
                    int x = s[l + len / 4] - 'a', y = s[mid] - 'a', z = s[r - len / 4] - 'a';
                    if (x == y) add(id(l + len / 4, z), id(l + len / 4, z), 1ll * len * len);
                    else if (y == z) add(id(r - len / 4, x), id(r - len / 4, x), 1ll * len * len);
                    else {
                        add(id(l + len / 4, z), id(l + len / 4, z), 1ll * len * len);
                        add(id(r - len / 4, x), id(r - len / 4, x), 1ll * len * len);
                    }
                }
            } else if (f[l][j - 1] != -1 || f[mid + 1][j - 1] != -1) {
                int S = f[l][j - 1] == -1 ? f[mid + 1][j - 1] : f[l][j - 1];
                if (S >> (s[mid] - 'a') & 1) continue;
                int x = lcp(l, mid - 1, mid + 1, r) + 1;
                if (piece(l + x, mid - 1) == piece(mid + 1 + x, r)) {
                    if (f[l][j - 1] == -1) {
                        int y = id(l + x - 1, s[mid + 1 + x - 1] - 'a');
                        add(y, y, 1ll * len * len);
                    } else {
                        int y = id(mid + 1 + x - 1, s[l + x - 1] - 'a');
                        add(y, y, 1ll * len * len);
                    }
                }
            }
        }
    }
    for (int i = id(1, 0); i <= id(n, 25); i++) {
        ans[i] += ans[i - 1];
        fans = max(fans, ans[i]);
    }
    printf("%lld\n", fans);
    return 0;
}