「UVA10559」Blocks

传送门
Luogu

解题思路

考虑区间 \(\text{DP}\)
\(f[i][j][k]\) 表示 \([i,j]\) 这段区间接上后面 \(k\) 个与 \(j\) 颜色相同的块得到的答案。
转移就是:
\(f[i][j][k] = \max\left\{f[i][j][0]+(k+1)^2\right\}\)
\(f[i][j][k] = \max\left\{f[i][p][k+1]+f[p+1][j-1][0]\right\}(p\in[i, j]\text{且}c_p=c_j)\)
第一个方程就是把后面那一坨一起消掉,再消掉前面。
第二个方程就是在中间找一个与 \(j\) 颜色相同的点 \(p\) ,把 \([p+1,j-1]\) 这段先消掉,然后让剩下的两坨拼起来再消。
写成记搜很方便的说

细节注意事项

  • 咕咕咕

参考代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <ctime>
#define rg register
using namespace std;
template < typename T > inline void read(T& s) {
 	s = 0; int f = 0; char c = getchar();
 	while (!isdigit(c)) f |= (c == '-'), c = getchar();
 	while (isdigit(c)) s = s * 10 + (c ^ 48), c = getchar();
 	s = f ? -s : s;
}

const int _ = 202;

int n, a[_], f[_][_][_], pre[_], las[_];

inline int dfs(int i, int j, int k) {
	if (i > j) return 0;
	if (f[i][j][k]) return f[i][j][k];
	f[i][j][k] = max(f[i][j][k], dfs(i, j - 1, 0) + (k + 1) * (k + 1));
	for (rg int p = pre[j]; p >= i; p = pre[p])
		f[i][j][k] = max(f[i][j][k], dfs(i, p, k + 1) + dfs(p + 1, j - 1, 0));
	return f[i][j][k];
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
#endif
	int T; read(T);
	for (rg int o = 1; o <= T; ++o) {
		memset(f, 0, sizeof f);
		memset(pre, 0, sizeof pre);
		memset(las, 0, sizeof las);
		read(n);
		for (rg int i = 1; i <= n; ++i) read(a[i]);
		for (rg int i = 1; i <= n; ++i) pre[i] = las[a[i]], las[a[i]] = i;
		printf("Case %d: %d\n", o, dfs(1, n, 0));
	}
	return 0;
}

完结撒花 \(qwq\)

posted @ 2019-10-27 07:26  Sangber  阅读(138)  评论(0编辑  收藏  举报