链接
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1500
题解
这题肯定从区间
dp
d
p
来入手,考虑对于区间
[i,j]
[
i
,
j
]
我加入第
j
j
个元素,那么这个元素可能和前面的某些或者和后面的某些一起消掉,这种前后关联的,有一个套路就是加一维表示后面的影响
表示在
[i,j]
[
i
,
j
]
区间连着后面的
k
k
个颜色和相同的块一起消掉的最大获利
转移就是要么第
j
j
个和后面个一起消掉,前面的单独算,
f[i][j][k]←(k+1)2+f[i][j−1][0]
f
[
i
]
[
j
]
[
k
]
←
(
k
+
1
)
2
+
f
[
i
]
[
j
−
1
]
[
0
]
要么看下第
j
j
个和前面的哪些一起消,枚举,如果
c[p]=c[j]
c
[
p
]
=
c
[
j
]
(颜色相同),
f[i][j][k]←f[i][p][k+1]+f[p+1][j][0]
f
[
i
]
[
j
]
[
k
]
←
f
[
i
]
[
p
]
[
k
+
1
]
+
f
[
p
+
1
]
[
j
]
[
0
]
,至于为啥只枚举颜色相同的,可以想一下,显然我可以把第
j
j
<script type="math/tex" id="MathJax-Element-1959">j</script>个放到最后一步消除,那么这些要最后一步消掉的就把这个区间分成好几块,每一块我肯定单独消,拆掉消只会让答案变大
收获
很多题,要把它的各种性质找到,就能让最后的算法变得非常简单
代码
//dp
#include <bits/stdc++.h>
#define maxn 210
#define sqr(x) ((x)*(x))
using namespace std;
int f[maxn][maxn][maxn], N, c[maxn];
void init()
{
int i, j;
memset(f,-1,sizeof(f));
scanf("%d",&N);
for(i=1;i<=N;i++)scanf("%d",c+i);
}
int dp(const int i, const int j, const int k)
{
int p;
if(i>j)return sqr(k);
if(f[i][j][k]!=-1)return f[i][j][k];
f[i][j][k]=dp(i,j-1,0)+sqr(k+1);
for(p=i;p<j;p++)if(c[p]==c[j])f[i][j][k]=max(f[i][j][k],dp(i,p,k+1)+dp(p+1,j-1,0));
return f[i][j][k];
}
int main()
{
int T, c=1;
for(scanf("%d",&T);c<=T;c++)init(), printf("Case %d: %d\n",c,dp(1,N,0));
return 0;
}