NKOJ-3698 方块消除

P3698方块消除
时间限制 : - MS 空间限制 : 65536 KB
评测说明 : 时限1000ms

问题描述
有n个带颜色的方块排成一排,相同颜色的方块连成一段同色区域,如下图所示:

游戏时,玩家可以任选一段同色区域,将其消去。设消去的这段包含x个相同颜色的方块,则此次消除操作的得分为x^2。然后右边的所有方块会往左边合拢。
如下图所示:
(脑补)
第一步将白色一段消除,得分16;
第二步将褐色一段消除,得分9;
第三步将橙色一段消除,得分4;
总分29
你的任务是对于给定的一排方块,计算消除它们能得到的最大得分。

输入格式
第一行,一个整数n
第二行,描述初始状态的一排方块,由n个空格间隔的整数表示,每个整数表示一种颜色。整数的范围在[1,n]

输出格式
一行,一个整数,表示最大得分

样例输入 1
9
1 2 2 2 2 3 3 3 1
样例输出 1
29

样例输入 2
8
1 2 2 3 1 3 2 1
样例输出 2
18

提示
1<=n<=200

解题思路

这道题目的状态规定的思路大概就是
一边有一段长度为k的相同色块的方块,你留不留
然后就很纠结对吧,因为加入按照以前的思路,只定一个[L,R]根本知不道他们留不留,留多少个
所以我们就增加一个k,来记录留下的相同色块的个数(k表示一端有k个方块颜色相同(应该是最长的相同方块的数量))
于是对于一段区间[l,r+k],决策有两种方式:
    ①保留[r+1,r+k],然后与[l,r]中保留的同色色块合并
    ②消除[r+1,r+k],然后计算[l,r]的最大值
于是规定状态:res[l][r][k]为[l,r+k]的最大值
(sq用于记录方块的颜色)
于是对于①有:
    res[l][r][k]=max(DP[l,L,k]+DP[L+1,r,0])其中,L为遍历[l,r]后满足sq[L]=sq[r]!=sq[L+1]的所有值
对于②有sq[l,r,k]=DP(l,r,0)+k*k

具体解释一下①号状态:
    对于k,假如说这段区间类似于
        --abcd--efg--hijk---
    我们要保留'-'所代表的区域,而此处的k为3,明显离最大值是很远的,而且并不一定所有的'-'连起来就是最大值
    但是我们知道,如果右边的一段'-'和右边数起第二段长度为2的'-'要合并,那么并成5个连续的块一定是最大值
    所以我们就从左边开始,依次寻找与'-'相同的段,且每次都寻找尽量长的段
    于是就有条件:
        sq[L]=sq[r]!=sq[L+1]
    满足这个条件就一定寻找的是当前最长段,然后将[L+1,R]消除(就是把这两段之间的方块消除),那么就能连成一段更长段
    经过反复的迭代,每一种颜色一定会把所有的长度(当然是一段段最长段加起来)都遍历一遍
    (请配合草稿本与智商一起查看以上文字)

详情看代码
上述思路不完善处有待修改,不要期待
另外…这道题真的有魔力,早上起来自己推这个方程就推睡着了…

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int sq[234],res[234][234][234];

int DP(int l,int r,int k)
{
    if(l>r)return 0;//请尝试把这句话删去,体会一下我中午调试不起的痛苦
    if(res[l][r][k]!=-1)return res[l][r][k];
    int R=r;
    while(sq[R]==sq[r]&&R>=l)R--;
    res[l][r][k]=DP(l,R,0)+(r-R+k)*(r-R+k);
    for(int L=l;L<=R;L++)if(sq[L]==sq[r]&&sq[L+1]!=sq[r])res[l][r][k]=max(res[l][r][k],DP(l,L,r-R+k)+DP(L+1,R,0));
    return res[l][r][k];
}

int main()
{
    int n;
    scanf("%d",&n);
    memset(res,-1,sizeof(res));
    for(int i=1;i<=n;i++)scanf("%d",&sq[i]);
    cout<<DP(1,n,0);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值