45th ICPC昆明 C.Cities(区间dp)

题目链接

Description

有n个点,每个点有自己的颜色(并且每种颜色出现次数不超过15次),每次操作可以把一段连续且颜色相同的点染成任意一种颜色,求把所有点染成相同颜色的最小操作次数。
1n5000

Solution

首先我们可以贪心,把连续的一段缩成一个点。

区间dpdp[l][r]表示把[l,r]这一段染成相同颜色的最小操作次数。
朴素的区间dp转移是n3的。
但是这里有一个条件,每种颜色出现次数不超过15次,我们改变状态的定义,dp[l][r]表示把[l,r]这一段染成与l点相同的颜色的最小操作次数,
预处理缩点之后的每个点的下一个相同颜色的点在哪个位置,利用这些点进行状态的转移。
假如与l点颜色相同的且在[l,r]这一段的一些点是mid,那么dp[l][r]=min(dp[l][r],dp[l][mid1]+dp[mid][r])

#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
using ll = long long;
void solve() {
int n; cin >> n;
vector<int> a(n + 1, -1), nxt(n + 1), pos(n + 1, n + 1);
vector<vector<int>> dp(n + 2, vector<int> (n + 2, 1 << 29));
for (int i = 1;i <= n;i++) {
cin >> a[i];
if (a[i] == a[i - 1] && i > 1) {
i --, n --;
}
}
for (int i = n;i > 0;i--) {
nxt[i] = pos[a[i]];
pos[a[i]] = i;
dp[i][i] = 0;
}
for (int len = 1;len < n;len ++) {
for (int l = 1;l + len <= n;l ++) {
int r = l + len;
dp[l][r] = min(dp[l + 1][r], dp[l][r - 1]) + 1;
int mid = nxt[l];
while (mid <= r) {
dp[l][r] = min(dp[l][r], dp[l][mid - 1] + dp[mid][r]);
mid = nxt[mid];
}
}
}
cout << dp[1][n] << endl;
}
signed main(void) {
cin.tie(nullptr), cout.tie(nullptr) -> ios::sync_with_stdio(false);
int t; cin >> t;
while (t --)
solve();
return 0;
}

另一种做法:
如果一段区间两个端点的颜色相同,那么我们对这一段区间染色时,相比于两个端点的颜色不同可以少一次染色操作,那么贪心的想,需要最大化区间两个端点颜色相同时的染色次数。

转移不是很彻底的懂,这种做法当作开拓思路了。

#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
using ll = long long;
void solve() {
int n; cin >> n;
vector<int> a(n + 1, -1), nxt(n + 1), pos(n + 1, n + 1);
vector<vector<int>> dp(n + 1, vector<int> (n + 1, 0));
for (int i = 1;i <= n;i++) {
cin >> a[i];
if (a[i] == a[i - 1] && i > 1) {
i --, n --;
}
}
for (int i = n;i > 0;i--) {
nxt[i] = pos[a[i]];
pos[a[i]] = i;
}
for (int len = 1;len < n;len ++) {
for (int l = 1;l + len <= n;l ++) {
int r = l + len;
dp[l][r] = max(dp[l + 1][r], dp[l][r - 1]);
int mid = nxt[l];
while (mid <= r) {
dp[l][r] = max(dp[l][r], dp[l + 1][mid - 1] + dp[mid][r] + 1);
mid = nxt[mid];
}
}
}
cout << n - 1 - dp[1][n] << endl;
}
signed main(void) {
cin.tie(nullptr), cout.tie(nullptr) -> ios::sync_with_stdio(false);
int t; cin >> t;
while (t --)
solve();
return 0;
}
posted @   Coldarra  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示