题意:一排有颜色的方块,每次可以消除相邻的颜色相同的块,得分为方块个数的平方,消除后剩下的方块会合并,问怎样消除方块使得总得分最大。
方法:
合并初始相邻相同的块,得到颜色数组c和对应的长度len,dp[i][j][k]表示i~j区间,与后面k个相同颜色块一起消除得分的最大值(当然k个块的颜色必须与j相同),考虑len[j]和k这一段怎么消除,有两种可能:
1.单独消除,dp[i][j][k]=dp[i][j-1][0]+(len[j]+k)^2;
2.和前面的一起消除,假设前面的一起消除的块最后一块为p,那么dp[i][j][k]=dp[i][p][k+len[j]]+dp[p+1][j-1][0]。
可以根据p和j的颜色相同以及k的范围来优化一下。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=205;
int n,m,ans,tot,a[maxn],c[maxn],len[maxn],pos[maxn],last[maxn];
int dp[maxn][maxn][maxn],num[maxn][maxn];
void solve()
{
int i,j,k,p,l;
memset(pos,0,sizeof(pos));
for(i=1;i<=n;i++)
{
last[i]=pos[c[i]];
pos[c[i]]=i;
}
memset(num,0,sizeof(num));
for(i=tot;i>=1;i--)
{
for(j=1;j<=n;j++)
{
if(j==c[i]) num[j][i]=num[j][i+1]+len[i];
else num[j][i]=num[j][i+1];
}
}
memset(dp,0,sizeof(dp));
for(l=1;l<=tot;l++)
{
for(i=1;i<=tot;i++)
{
j=i+l-1;
if(j>tot) break;
for(k=0;k<=num[c[j]][j+1];k++)
{
dp[i][j][k]=dp[i][j-1][0]+(len[j]+k)*(len[j]+k);
for(p=last[j];p>=i;p=last[p])
{
if(p>j)
continue;
dp[i][j][k]=max(dp[i][j][k],dp[i][p][k+len[j]]+dp[p+1][j-1][0]);
}
}
}
}
ans=dp[1][tot][0];
}
int main()
{
int i,j,t,ca;
scanf("%d",&t);
ca=0;
while(t--)
{
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
tot=0;
memset(len,0,sizeof(len));
for(i=1;i<=n;)
{
tot++;
c[tot]=a[i];
while(i<=n&&a[i]==c[tot])
{
i++;
len[tot]++;
}
}
solve();
ca++;
printf("Case %d: %d\n",ca,ans);
}
}