题意:给定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颜色相同的盒子;

View Code
 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 }