题目
T(T<=15)组样例,每次给出n(n<=200)个方块,第i个整数ci代表方块的颜色(1<=ci<=n),
每次你可以手动消除一段连续的长度为x的方块,并获得这段方块带来的价值,
消除之后,后面的方块会跟上来,但并不会产生消除的连锁反应,需要你指定才会发生消除
求消完所有方块后的最大价值之和
思路来源
https://www.cnblogs.com/Tieechal/p/11637638.html 清楚明白的讲解
题解
经典区间dp消除问题的例题,也是入坑消除问题的第一道题,定义的状态很神奇
[Luogu2135] 方块消除,UVA10559 Blocks,一道题出了三遍
方块消除不用尺取把相同颜色的合在一起,而Blocks需要
dp[l][r]并不能解决问题,因为可能先消r后面的一段,使和r相同的颜色紧挨着r,这样的决策,使得dp[l][r]不能固定下来
因此多开一维,dp[l][r][lx]代表对于[l,r]区间,当前有lx个方块和b[r]颜色相同,紧跟在r后面没有被消除
本次决策有两种,决策是基于r这种颜色的,
一种是本次利用r的价值,把(lx+b[r])个消掉,递归到dp[l][r-1][0]的情形,
另一种为了以后更大的r的价值,是从[l,r-1]中找到一个和r颜色相同的位置i,先消掉[i,r-1]这段,从而把(lx+b[r])个续到i后面去
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=205;
int t,n,m,a[N],b[N],v[N],dp[N][N][N];
int dfs(int l,int r,int lx){
int &ans=dp[l][r][lx];
if(~ans)return ans;
int all=b[r]+lx;
if(l==r){
return ans=all*all;
}
ans=0;
ans=max(ans,dfs(l,r-1,0)+all*all);
for(int i=l;i<r;++i){
if(v[i]==v[r]){
ans=max(ans,dfs(i+1,r-1,0)+dfs(l,i,all));
}
}
return ans;
}
int main(){
scanf("%d",&t);
for(int ca=1;ca<=t;++ca){
memset(dp,-1,sizeof dp);
scanf("%d",&n);
m=0;
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
if(a[i]!=a[i-1])b[++m]=1,v[m]=a[i];
else b[m]++;
}
printf("Case %d: %d\n",ca,dfs(1,m,0));
}
return 0;
}