Blocks
给出n个排成一排的箱子,第i个箱子的颜色为(a_i),每次可以选择一段相邻的同颜色删去,记该段长度(q),则增加(q^2)的权值,问最大的权值。
解
首先可以把一段同色缩成一个箱子,记下个数(len[i]),注意到问题的区间性,考虑区间递推,设(f[i][j])表示删去([i,j])的箱子的最大权值,现在问题是如何表现删去箱子后箱子相邻,发现删掉箱子相邻,既有一堆箱子靠在了同色的后面,故猜想是否只要表现一个箱子后面所接的箱子个数。
因此设(f[i][j][k])前两维同上意,k为与(a_j)颜色相同的k个箱子接着j后面,设(g_i)为i以后与i同色的箱子个数(显然不包括i),注意,接下来是对一段箱子进行离散化后的讨论,而不是看一个箱子,故不难有
[f[i][j][k]=maxegin{cases}f[i][j-1][0]+(k+len[j])^2\max_{p=i}^{j-1}f[i][p][k+len[j]]+f[p+1][j][0](a[j]==a[p])end{cases}
]
其中(g_jgeq k)
边界:(f[i][i][j]=(j+len[i])^2)其中i,j都要保证是合法的边界
答案:(f[1][n][0])
参考代码
#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
using namespace std;
int a[205],b[205],bt,len[205],
dp[205][205][205],g[205];
il int pow2(int),max(int,int);
int main(){
int lsy;
scanf("%d",&lsy);
for(int h(1);h<=lsy;++h){
memset(g,0,sizeof(g));
memset(dp,-2,sizeof(dp));
memset(len,0,sizeof(len));
int n;scanf("%d",&n),bt&=0;
for(int i(1);i<=n;++i){scanf("%d",&a[i]);
if(b[bt]!=a[i])b[++bt]=a[i];++len[bt];}
for(int i(bt),j;i;--i)
for(j=i+1;j<=bt;++j)
if(b[j]==b[i])g[i]+=len[j];
for(int i(1),j;i<=bt;++i)
for(j=0;j<=g[i];++j)
dp[i][i][j]=pow2(j+len[i]);
for(int i,j(1),k,p;j<=bt;++j)
for(i=j-1;i;--i)
for(k=0;k<=g[j];++k){
dp[i][j][k]=dp[i][j-1][0]+pow2(len[j]+k);
for(p=i;p<j;++p)
if(b[p]==b[j])
dp[i][j][k]=max(
dp[i][j][k],dp[i][p][len[j]+k]+
dp[p+1][j-1][0]);
}printf("Case %d: %d
",h,dp[1][bt][0]);
}
return 0;
}
il int max(int a,int b){
return a>b?a:b;
}
il int pow2(int x){
return x*x;
}