https://codeforces.com/contest/1114/problem/D
题目
给一串数字,首先选择一个位置,类似于画图,然后每一轮按照以下步骤:
- 可以将这个位置所在的连通块改成其他数字
问最少几步可以把所有数字变成一样的
题解
设dp[l][r][0/1]为把[l,r)范围变成和最左侧或最右侧数字一样需要的最少步数,
可以通过数学归纳证明
- 选择什么数字不重要,即使选择是中间的数字,步数一样不会变小
要注意的是有8种转移

$2 imes2+2 imes2$
其中有4种转移肯定不是最优,因为选择的点的位置不能变。
AC代码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 5007
int c[MAXN];
int dp[MAXN][MAXN][2];
int main() {
int n; scanf("%d", &n);
for(int i=0; i<n; i++) {
scanf("%d", &c[i]);
}
for(int i=0; i<n; i++) {
dp[i][i][0]=dp[i][i][1]=dp[i][i+1][0]=dp[i][i+1][1]=0;
}
for(int d=2; d<=n; d++) {
for(int l=0; l+d<=n; l++) {
int r=l+d;
dp[l][r][0]=dp[l][r][1]=0x3f3f3f3f;
const int cs[][2]={{l+1, r-1},{l, r-2}};
for(int k=0; k<2; k++) {
dp[l][r][0] = min(dp[l][r][0], dp[l+1][r][k]+int(c[cs[0][k]]!=c[l]));
dp[l][r][1] = min(dp[l][r][1], dp[l][r-1][k]+int(c[cs[1][k]]!=c[r-1]));
}
}
}
printf("%d
", min(dp[0][n][0], dp[0][n][1]));
return 0;
}