直接删除 c_r 和后面的 x 个数:如果 x + 1 < k,那么我们就要添加 k - x - 1 个数。所以这种转移的方程为 f(l, r, x) = f(l, r - 1, 0) + \max \{ 0, k - x - 1 \}(为什么 f(l, r - 1, 0) 第三个参数是 0?牢记我们状态定义的前提就是已经把 r 以后所有不等于 c_r 的数都删去了);
若存在 i \in [l, r] 且 c_i = c_r,那么我们也可以先删去 [i + 1, r - 1],然后再把 c_i, c_r 以及后面的 x 个数一起删除。这种转移的方程为 f(l, r, x) = f(i + 1, r - 1, 0) + f(l, i, x + 1)。
枚举所有转移取最小即可。
小优化
删除操作没有代价,因此长度大于等于 k 且可以被删除的区间没有意义,第三维的取值范围可以设为 [0, k - 1]。当然,转移方程也随之有一点小变化。
边界
### 复杂度分析
时间复杂度为 $\operatorname{O}(N^3K)$,但常数很小;空间复杂度为 $\operatorname{O}(N^2K)$。
## 实现
```cpp
#include <iostream>
using namespace std;
const int N = 100, K = 5;
int c[N + 5], f[N + 5][N + 5][K + 5];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++)
cin >> c[i];
for (int len = 1; len <= n; len++)
for (int l = 1, r = l + len - 1; r <= n; l++, r++)
for (int x = 0; x < k; x++)
{
f[l][r][x] = f[l][r - 1][0] + k - x - 1;
for (int i = l; i < r; i++)
if (c[i] == c[r])
f[l][r][x] = min(f[l][r][x], f[l][i][min(x + 1, k - 1)] + f[i + 1][r - 1][0]);
}
cout << f[1][n][0] << "\n";
return 0;
}
```