1. 程式人生 > >【Uva10559】Blocks(區間DP)

【Uva10559】Blocks(區間DP)

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\)

個格子的最大分數

  1. 直接消除,即左邊不考慮,為\(dp[i][j-1][0]+(len[j]+k)^2\)
  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)