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

cxqghzj·2024-04-28 23:58·26 次阅读

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

题意#

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

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

Sol#

唉,卡了好久。

考虑设 fi,j 表示 S 匹配到 iT 匹配到 j 的最小代价。

{fi,j+wi+1fi+1,jfi,jfi+1,j+1

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

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

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

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

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

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

Code#

Copy
#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 @   cxqghzj  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示
目录