【GDKOI 2021提高組DAY2】抄寫
阿新 • • 發佈:2021-08-11
\(\text{Solution}\)
\(dp\) 翻折就只需預處理迴文中心
\(Manacher\) 預處理即可
\(Code\)
#include<cstdio> #include<iostream> #define LL long long using namespace std; const int N = 1e6 + 5; int n, p[N << 1]; LL f[N << 1], cost[30], C; char s[N], str[N << 1]; inline void Manacher() { int len = n; str[0] = '@', str[1] = '#', n = 2; for(register int i = 1; i <= len; i++) str[n++] = s[i], str[n++] = '#'; str[n] = '$'; for(register int i = 1, mx = 0, id = 0; i <= n; i++) { p[i] = (i < mx ? min(p[id * 2 - i], mx - i) : 1); while (str[i + p[i]] == str[i - p[i]]) ++p[i]; if (i + p[i] > mx) mx = i + p[i], id = i; } } LL INF = 0x3f3f3f3f3f3f3f3f; LL tag[N << 3]; #define ls (p << 1) #define rs (ls | 1) #define mid ((l + r) >> 1) void build(int p, int l, int r) { tag[p] = INF; if (l == r) return; build(ls, l, mid), build(rs, mid + 1, r); } void update(int p, int l, int r, int x, int y, LL v) { if (x <= l && r <= y) return void(tag[p] = min(tag[p], v)); if (x <= mid) update(ls, l, mid, x, y, v); if (y > mid) update(rs, mid + 1, r, x, y, v); } LL query(int p, int l, int r, int x) { LL ret = tag[p]; if (l == r) return ret; if (x <= mid) ret = min(ret, query(ls, l, mid, x)); else ret = min(ret, query(rs, mid + 1, r, x)); return ret; } int main() { freopen("copy.in", "r", stdin); freopen("copy.out", "w", stdout); scanf("%d%lld", &n, &C); for(register int i = 0; i < 26; i++) scanf("%lld", &cost[i]); scanf("%s", s + 1), Manacher(); build(1, 1, n); for(register int i = 1; i <= n; i++) { if (str[i] == '#' || str[i] == '$') f[i] = f[i - 1]; else f[i] = f[i - 1] + cost[str[i] - 'a']; f[i] = min(f[i], query(1, 1, n, i) + C); update(1, 1, n, i + 1, min(i + p[i] - 1, n), f[i]); } printf("%lld\n", f[n]); }