【Uva10559】Blocks(區間DP)
阿新 • • 發佈:2017-12-29
log turn logs efi read etc body pre 數量 個格子的最大分數
Description
題意:有一排數量為N的方塊,每次可以把連續的相同顏色的區間消除,得到分數為區間長度的平方,然後左右兩邊連在一起,問最大分數為多少。
\(1\leq N\leq200\)
Solution
區間DP,對於一個連續的同色區間,可以直接消掉,或者從左邊或者右邊搞到和它同色的區間和在一起再一起消掉。
讀入序列時預處理一下,將各個連續同色區間處理為一個點,記錄它的顏色和長度,便於處理
然後就是區間DP啦,雖然要表示左邊和右邊,但是左邊狀態也可以表示為左邊序列的右邊,就只要開3維就行了
那麽\(dp[i][j][k]\)表示區間\(i\)到區間\(j\)且在區間\(j\)右邊添加\(k\)
- 直接消除,即左邊不考慮,為\(dp[i][j-1][0]+(len[j]+k)^2\)
- 考慮左邊,在\(j\)右邊枚舉\(p\),且\(color[j]==color[p]\),則為\(max\{dp[i][p][k+len[j]]+dp[p+1][j-1][0]\}\)
Code
#include <cstdio>
#include <algorithm>
#include <cstring>
#define sq(a) ((a)*(a))
#define N 210
using namespace std;
int T,col[N],dp[N][N][N],n,len[N];
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int DP(int l,int r,int k){
int &tmp=dp[l][r][k];
if (tmp>-1) return tmp;
tmp=DP(l,r-1,0)+sq(len[r]+k);
for(int p=l;p<r;++p){
if(col[p]!=col[r]) continue;
tmp=max(tmp,DP(l,p,k+len[r])+DP(p+1,r-1,0));
}
return tmp;
}
int main(){
T=read();
for(int Ca=1;Ca<=T;++Ca){
memset(dp,-1,sizeof(dp));
memset(len,0,sizeof(len));
int L=read(),a=read(),l=1;
n=0;
for(int i=2;i<=L;++i){
int b=read();
if(b==a) l++;
else{
col[++n]=a;
len[n]=l;
l=1;
a=b;
}
}
col[++n]=a,len[n]=l;
for(int i=1;i<=n;++i) {dp[i][i][0]=sq(len[i]);dp[i][i-1][0]=0;}
printf("Case %d: %d\n",Ca,DP(1,n,0));
}
return 0;
}
【Uva10559】Blocks(區間DP)