題目
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;
}