Blocks

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]=\max\begin{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_j\geq 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\n",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;
}
posted @ 2019-06-12 08:19  a1b3c7d9  阅读(200)  评论(0编辑  收藏  举报