经典区间dp 【方块消除】
题目传送门~
思路
求一个区间内分数的最大值,我们容易想到用区间dp来做这道题。
首先,我们来定义一下数组:
\(dp[l][r]\) 表示 将 \(l\)~\(r\) 这段区间消除得到的最大分数值。
\(color[l]\) 表示 \(l\) 这段区间的颜色。
\(len[l]\) 表示 \(l\) 这段区间的长度。
但是在写代码时,我们发现:如果在 \(r\) 后面有一段长度为 \(k\) 的区间颜色和 \(r\) 区间 一样,那么在消除 \(l\)~\(r\) 区间时,会顺带着把 \(k\) 区间也消除了。所以我们就加上一维数组来维护这个 \(k\) :
\(dp[l][r][k]\) 表示 消除 \(l\)~\(r\) 这段区间且在 \(r\)区间 后有 \(k\) 个与 \(r\) 区间颜色相同的方块的最大分数值。
接下来我们考虑状态的转移。
- 首先,我们可以直接消除 \(r\) 这一段区间,再加上消除 \(l\) ~ \(r-1\) 区间的最大值,那么转移方程就为:\[dp[l][r][k] = dp[l][r-1][0] + (len[r] + k)^2 \]
- 其次,我们可以枚举 \(l\)~\(r\) 间的一段区间 \(i\),使 \(i\) 区间的颜色与 \(r\) 区间的颜色相同,然后我们可以先消除 \(i+1\) ~ \(r-1\) 区间。这样的话, 就可以将 \(r\) 和 \(i\) 两个区间合并成一个颜色相同的区间,然后再计算消除 \(l\)~\(i\) 区间的最大值,那么转移方程就为:\[dp[l][r][k] = max (dp[l][i][len[r] + k] + dp[i +1][r -1][0]) \]
- 当然,\(l == r\) 时,我们直接返回 \((len[r]+k) ^2\) 即可。
代码
记忆化搜索
#include <cstdio>
using namespace std;
inline char nc () {
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread (buf, 1, 100000, stdin), p1 == p2) ? EOF :*p1++;
}
inline int read () {
register int x(0), f(1);
char ch = nc ();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = ~f +1;
ch = nc ();
}
while (ch <= '9' && ch >= '0') {
x = (x << 3) + (x << 1) + (ch ^48);
ch = nc ();
}
return x *f;
}
inline int max (int a, int b) {
return a > b ? a :b;
}
int n;
int color[55];
int len[55];
int qwq[55][55][555];
int dfs (int l, int r, int k) {
if (qwq[l][r][k]) return qwq[l][r][k];
if (l == r) return (len[r] + k) * (len[r] + k);
qwq[l][r][k] = dfs (l, r - 1, 0) + (len[r] + k) * (len[r] + k);
for (register int i(l); i < r - 1; ++i)
if (color[i] == color[r])
qwq[l][r][k] = max (qwq[l][r][k], dfs (l, i, len[r] + k) + dfs (i + 1, r - 1, 0));
return qwq[l][r][k];
}
int main () {
n = read ();
for (register int i(1); i <= n; ++i) color[i] = read ();
for (register int i(1); i <= n; ++i) len[i] = read ();
printf ("%d", dfs (1, n, 0));
return 0;
}