题目
分析
不能直接设计 d p [ l ] [ r ] dp[l][r] dp[l][r] 因为你消除了其中一部分,左右又会并过来一部分,因而你不知道实际消掉了些什么,因此加一维 d p [ l ] [ r ] [ x ] dp[l][r][x] dp[l][r][x] 表示 r r r 右边还有 x x x 个和 r r r 一样颜色的,消掉这些东西获得的分数,转移的时候枚举区间中和 r r r 一样颜色的,把区间变成两截即可。
代码
#include <bits/stdc++.h>
int Read() {
int x = 0; bool f = false; char c = getchar();
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = x * 10 + (c ^ 48), c = getchar();
return f ? -x : x;
}
typedef long long LL;
const int MAXN = 200;
int N;
int C[MAXN + 5];
int Nxt[MAXN + 5], Adj[MAXN + 5];
int Dp[MAXN + 5][MAXN + 5][MAXN + 5];
int Dfs(const int &lft, const int &rgt, const int &k) {
if (lft > rgt) return 0;
if (Dp[lft][rgt][k]) return Dp[lft][rgt][k];
int &ret = Dp[lft][rgt][k];
ret = Dfs(lft, rgt - 1, 0) + (k + 1) * (k + 1);
for (int i = Nxt[rgt]; i >= lft; i = Nxt[i])
ret = std::max(ret, Dfs(lft, i, k + 1) + Dfs(i + 1, rgt - 1, 0));
return ret;
}
int main() {
int T; scanf("%d", &T);
for (int cas = 1; cas <= T; ++cas) {
scanf("%d", &N);
for (int i = 1; i <= N; i++) {
scanf("%d", &C[i]);
Nxt[i] = Adj[C[i]];
Adj[C[i]] = i;
}
printf("Case %d: %d\n", cas, Dfs(1, N, 0));
memset(Dp, 0, sizeof Dp);
memset(Nxt, 0, sizeof Nxt);
memset(Adj, 0, sizeof Adj);
}
return 0;
}