ABC400F Happy Birthday! 3

题目链接

解题思路

初步观察

首先,必定存在一个位置,使得环从那里断成链之后,答案不变。

对于一条链,操作两两之间,如果不是不相交,就是包含关系,不然必定不优。

具体做法

题目给出的 \(b+X_c\) 这个式子中,既有与区间长度 \(b\),又有和具体颜色有关的 \(X_c\)
直接贪心我们难以平衡这两者。

此时,再根据初步观察的“操作之间不相交/包含”的性质我们容易对链的情况设计出一个区间 \(\text{DP}\)

\(f_{l,r}\) 为:把区间 \([l,r]\) 染成最终颜色的方案数。
有下列几种转移:

  1. \(l\) 点单独染色
  2. 选择一个 \([l+1,r]\) 中和 \(l\) 同色位置 \(k\),并且把 \(l\) 点和 \(k\) 点一起染色,多出来的贡献是 \([l,k-1]\) 这一段。

这是链的情况。原题目中环的情况可以考虑将数组复制一遍拼接到尾部,然后对所有长为 \(n\) 的区间取个 \(\min\) 就是答案。

代码实现

点击查看代码
#include <bits/stdc++.h>
#define FL(i, a, b) for (int i = (a); i <= (b); ++i)
#define FR(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
typedef long long ll;
constexpr int N = 810;
constexpr ll INF = 1e14;
int n, c[N], x[N];
ll f[N][N];
int main() {
    scanf("%d", &n);
    FL(i, 1, n) {
        scanf("%d", &c[i]);
        c[n + i] = c[i];
    }
    FL(i, 1, n) {
        scanf("%d", &x[i]);
    }
    FL(len, 1, n) {
        FL(l, 1, n * 2 - len + 1) {
            int r = l + len - 1;
            f[l][r] = x[c[l]] + 1 + f[l + 1][r];
            FL(k, l + 1, r) {
                if (c[l] == c[k]) {
                    f[l][r] = min(f[l][r], f[l + 1][k - 1] + f[k][r] + (k - l));
                }
            }
        }
    }
    ll ans = INF;
    FL(i, 1, n) {
        ans = min(ans, f[i][i + n - 1]);
    }
    printf("%lld\n", ans);
    return 0;
}
posted @ 2025-04-09 16:48  徐子洋  阅读(29)  评论(0)    收藏  举报