1. 程式人生 > 其它 >【GDKOI 2021提高組DAY2】抄寫

【GDKOI 2021提高組DAY2】抄寫

\(\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]);
}