Description
有n个点,每个点有自己的颜色(并且每种颜色出现次数不超过15次),每次操作可以把一段连续且颜色相同的点染成任意一种颜色,求把所有点染成相同颜色的最小操作次数。
\(1\leq n \leq 5000\)
Solution
首先我们可以贪心,把连续的一段缩成一个点。
区间\(dp\),\(dp[l][r]\)表示把\([l,r]\)这一段染成相同颜色的最小操作次数。
朴素的区间\(dp\)转移是\(n^3\)的。
但是这里有一个条件,每种颜色出现次数不超过15次,我们改变状态的定义,\(dp[l][r]\)表示把\([l,r]\)这一段染成与\(l\)点相同的颜色的最小操作次数,
预处理缩点之后的每个点的下一个相同颜色的点在哪个位置,利用这些点进行状态的转移。
假如与\(l\)点颜色相同的且在\([l,r]\)这一段的一些点是\(mid\),那么\(dp[l][r] = min(dp[l][r], dp[l][mid - 1] + 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;
}
标签:45th,颜色,int,pos,len,ICPC,--,Cities,dp
From: https://www.cnblogs.com/coldarra/p/16867583.html