YC275A [ 20240418 CQYC省选模拟赛 T1 ] 编辑(edit)

题意

给定一个字符串 \(S\),每次可以删除每种字符的第一个字符或最后一个字符,删除 \(S_i\) 需要付出 \(w_i\) 的代价。

问将 \(S\) 变为 \(T\) 所需的所有代价。

Sol

唉,卡了好久。

考虑设 \(f_{i, j}\) 表示 \(S\) 匹配到 \(i\)\(T\) 匹配到 \(j\) 的最小代价。

\[\begin{cases} f_{i, j} + w_{i + 1} \to f_{i + 1, j} \\ f_{i, j} \to f_{i + 1, j + 1} \end{cases} \]

注意到第一个转移需要满足当前 \(j\) 早于 \(S_i\)\(T\) 出现的第一个位置或 \(j + 1\) 晚于 \(S_i\)\(T\) 出现的最后一个位置。

考虑按照出现的第一个和最后一个位置分段。

注意到此时每一段对于第一个转移的限制相同,也就是说对于 \(j \in [l, r]\),只要 \(S_i\) 满足第一个转移,就一定不会产生第二个转移。

于是我们考虑推 \(j\),对于每一段挑出不满足第一个转移的限制的字符,使用哈希/KMP暴力匹配即可。

关键点在于分界点的特判,因为分界点可能存在同时满足两个限制,显然是可以将分界点单独挑出转移,但是这样太麻烦了。

集中注意力可以发现对于第一个位置的点可以扔到下一段计算,而对于最后位置的点则直接在当前段计算。

Code

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#include <bitset>
#include <vector>
#define int __int128
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 = 2e5 + 5, inf = 2e18, mod = 100000000000000049;

char strbuf[N];

array <int, 27> pre, suf;
bitset <27> vis;

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

void gethash(array <int, N> &Hs, string &s, int l, int r) {
    Hs[0] = 0;
    for (int i = l; i <= r; i++)
        Hs[i - l + 1] = Hs[i - l] * (__int128)131ll % mod + s[i];
    return;
}

array <int, N> Hs1, Hs2, idx;
array <int, N> w;

#define upd(x, y) (x = min(x, y))

bitset <27> tag;

bool _edmer;
signed main() {
    cerr << (&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n";
    scanf("%s", strbuf);
    string s = strbuf;
    int n = s.size(); s = " " + s;
    scanf("%s", strbuf);
    string t = strbuf;
    int m = t.size(); t = " " + t;
    idx[0] = 1;
    for (int i = 1; i <= n; i++)
        w[i] = read(), idx[i] = idx[i - 1] * 131ll % mod;

    for (int i = 1; i <= m; i++) {
        if (!vis[t[i] - 'a'])
            vis[t[i] - 'a'] = 1, pre[t[i] - 'a'] = i;
        suf[t[i] - 'a'] = i;
    }

    f[0].fill(inf), f[1].fill(inf), f[0][0] = 0;
    for (int i = 1; i <= n; i++)
        f[0][i] = f[0][i - 1] + w[i];

    int l = 1, r = 0, pl = 0;
    for ( ; l <= m; l = r + 1, pl ^= 1) {
        r++;
        while (suf[t[r] - 'a'] != r && pre[t[r + 1] - 'a'] != r + 1) r++;
        if (pre[t[l] - 'a'] == l) tag[t[l] - 'a'] = 1;
        string tp = " ";
        vector <int> isl(1, 0), psl(1, 0);
        int len = 0, lst = 0;
        for (int i = 1; i <= n; i++)
            if (tag[s[i] - 'a'])
                tp.push_back(s[i]), isl.push_back(lst), psl.push_back(i), len++;
            else lst += w[i];
        gethash(Hs1, t, l, r), gethash(Hs2, tp, 1, len);
        f[pl ^ 1].fill(inf);

        /* for (int i = 1; i <= len; i++) */
            /* write(isl[i]), putchar(32); */
        /* puts(""); */

        for (int i = 1; i + (r - l) <= len; i++) {
            if (Hs1[r - l + 1] == (Hs2[i + (r - l)] -
                Hs2[i - 1] * idx[r - l + 1] % mod + mod) % mod)
                upd(f[pl ^ 1][psl[i + (r - l)]],
                    f[pl][psl[i] - 1] + isl[i + (r - l)] - isl[i]);
        }
        if (suf[t[r] - 'a'] == r) tag[t[r] - 'a'] = 0;
        for (int i = 1; i <= n; i++)
            if (!tag[s[i] - 'a'])
                upd(f[pl ^ 1][i], f[pl ^ 1][i - 1] + w[i]);
    }
    if (f[pl][n] == inf) puts("-1");
    else write(f[pl][n]), puts("");
    return 0;
}
posted @ 2024-04-28 23:58  cxqghzj  阅读(11)  评论(0编辑  收藏  举报