题意:给定n个不同颜色的盒子,连续的相同颜色的k个盒子可以拿走,权值为k*k,求把所有盒子拿完的最大权值。
题解:记忆化搜索,dp[ll][rr][kk]代表在区间[ll,rr]取盒子,其中ll前面有k个盒子颜色和rr一样,可以重叠在rr上消去。
那么,dp[ll][rr][kk]=max(dp[ll][i][kk+len[rr]]+dp[i+1,rr-1][0],dp[ll][rr-1][0]+pow(len[rr]+kk)),i是所有位于[ll,rr-1]区间且与rr颜色相同的盒子;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int dp[205][205][205]; 6 int col[205],len[205]; 7 inline int pow(int x) 8 { 9 return x*x; 10 } 11 int dfs(int ll,int rr,int kk) 12 { 13 if(ll>rr) 14 return 0; 15 else if(dp[ll][rr][kk]) 16 return dp[ll][rr][kk]; 17 else if(ll==rr) 18 return dp[ll][rr][kk]=pow(kk+len[rr]); 19 else 20 { 21 int ans=dfs(ll,rr-1,0)+pow(len[rr]+kk); 22 for(int i=rr-1;i>=ll;i--) 23 if(col[i]==col[rr]) 24 ans=max(ans,dfs(ll,i,kk+len[rr])+dfs(i+1,rr-1,0)); 25 return dp[ll][rr][kk]=ans; 26 } 27 } 28 int main() 29 { 30 int T,ca=0; 31 for(scanf("%d",&T);T;T--) 32 { 33 memset(dp,0,sizeof(dp)); 34 int n,num=0,c; 35 scanf("%d",&n); 36 scanf("%d",&col[0]); 37 len[0]=1; 38 for(int i=1;i<n;i++) 39 { 40 scanf("%d",&c); 41 if(col[num]==c) 42 len[num]++; 43 else 44 col[++num]=c,len[num]=1; 45 } 46 printf("Case %d: %d\n",++ca,dfs(0,num,0)); 47 } 48 return 0; 49 }