AcWing3996 涂色
涂色
题意
给定一个长度为 \(n\) 的序列 \(a\) ,每次操作可以选择颜色相同的若干相邻元素,修改为任意数字,问最少修改几次使得序列 \(a\) 元素全部相同。
分析
区间DP,设 \(f(i, j)\) 表示将范围 \([i, j]\) 的元素修改成同一元素。
- 如果 \(a_i, a_j\) 元素相同,转移成将 \([i+1, j-1]\) 的元素修改为 \(a_i\) 。
- 如果 \(a_i, a_j\) 元素相同,考虑决策,把 \([i+1, j]\) 修改为 \(a_i\) 或者将 \([i, j-1]\) 修改为 \(a_j\) 。取 \(min\) 即可。
注意,我们需要把相同的元素(连通块)拼成一个同一个元素。
Code
#include <iostream>
using namespace std;
const int N = 5050;
int a[N], w[N], f[N][N];
int main ()
{
int n, m = 0; cin >> n;
for (int i = 1; i <= n; i ++ ) cin >> a[i];
for (int i = 1; i <= n; i ++ ) if (a[i] != a[i-1]) w[++m] = a[i];
for (int len = 2; len <= m; len ++ )
{
for (int l = 1; l + len - 1 <= m; l ++ )
{
int r = l + len - 1;
if (w[l] != w[r]) f[l][r] = min(f[l+1][r], f[l][r-1]) + 1;
else f[l][r] = f[l+1][r-1] + 1;
}
}
cout << f[1][m] << endl;
return 0;
}