[poj1390]Blocks(方块消除)

题目大意:给定一序列,可点击某一位置消除与其相邻且相同的方块,得分为$len*len$,求最大得分。

解题关键:关键是状态的构造,首先离散化一下,令$dp[i][j][k]$表示序列$i-j$且后面有$k$个与该序列最后位置相同的元素,

则$dp[i][j][k]$可以由两种情况转化而来,

1、最后一部分自己消除 $dp[i][j][k]=dp[i][j-1][0]+(k+len[j])*(k+len[j])$

2、最后一部分和该序列中前面的某一部分消除,假设坐标pos与r颜色相同 $dp[i][j][k]=dp[i][pos][k+len[j]]+dp[pos+1][j-1][0]$

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
int t,n,dp[202][202][202],a[202],len[202],clr[202],num;
int dfs(int l,int r,int k){
    if(l>r) return 0;
    if(dp[l][r][k]) return dp[l][r][k];
    dp[l][r][k]=dfs(l,r-1,0)+(k+len[r])*(k+len[r]);
    for(int i=l;i<r;i++){
        if(clr[i]==clr[r]) dp[l][r][k]=max(dp[l][r][k],dfs(l,i,k+len[r])+dfs(i+1,r-1,0));
    }
    return dp[l][r][k];
}
int main(){
    scanf("%d",&t);
    for(int ca=1;ca<=t;ca++){
        memset(dp,0,sizeof dp);
        memset(len, 0, sizeof len);
        num=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",a+i);
        for(int i=0;i<=n;i++){
            if(a[i]!=a[i-1]) clr[++num]=a[i],len[num]=1;
            else len[num]++;
        }
        int ans=dfs(1,num,0);
        printf("Case %d: %d
",ca,ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/elpsycongroo/p/7812183.html