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;
}