题解:AT_abc400_f [ABC400F] Happy Birthday! 3
首先考虑序列。令
考虑
- 独自操作。即
f(l,r-1) + X_{C_r}+1 \longrightarrow f(l, r) 。 - 考虑枚举
y \in [l, r-1] 且C_y = C_r 。当y 这个位置变成目标状态时,我们考虑扩展这次操作的区间,使其右端点覆盖到r 。然后再操作[y+1,r-1] 。即f(l,y)+r-y+f(y+1,r-1) \longrightarrow f(l, r) 。因为是扩展,那么X_{c_r} 的贡献就不用再算一次(已经在f(l,y) 里算过了),将代价直接加上区间扩展的长度(r-y )即可。
然后考虑环。最直接的思路是倍长序列后做上面的区间 DP,然后求
为什么?如果不存在这个位置,那么每次操作的区间的端点一定被操作过至少两次(除了这次还有另一次)。考虑最后一次操作的区间是
long long 是一定要开的。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 810;
int n, c[N], x[N];
int f[N][N];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; ++ i ) cin >> c[i], c[i + n] = c[i];
for (int i = 1; i <= n; ++ i ) cin >> x[i];
for (int i = 1; i <= n * 2; ++ i ) {
f[i][i] = x[c[i]] + 1;
}
for (int len = 2; len <= 2 * n; ++ len )
for (int l = 1, r = len; r <= 2 * n; ++ l, ++ r ) {
f[l][r] = f[l][r - 1] + f[r][r];
for (int x = l; x < r; ++ x )
if (c[x] == c[r]) f[l][r] = min(f[l][r], f[l][x] + r - x + f[x + 1][r - 1]);
}
int res = 1e18;
for (int l = 1, r = n; r <= 2 * n; ++ l, ++ r ) res = min(res, f[l][r]);
cout << res;
return 0;
}