题目大意:

n 个木块排成一列,每个木块有一个颜色,每次,你都可以点击一个木块,这样被点击的木块以及和它相邻并且同色的木块就会被消除。如果一次性消除了 k 个木块,就会得到 分,求最高得分。


算法分析:

首先,会想到贪心,但很容易发现有些最优解是消除了单个木块,让更长的相同颜色木块拼在一起。所以,贪心策略行不通。

于是,想到了区间DP

做过版子题(石子合并)应该会很容易想到:

设 tot 表示原序列分成的颜色段的段数。

len[i] 表示第 i 个颜色段的长度。

color[i] 表示第 i 个颜色段的颜色。

dp[i][j] 表示消除第 i 段到第 j 段之间所有木块的最高得分。

然而,我们发现,如果单纯这么转移的话,当第 j 段后面仍然有和第 j 段前面的颜色段颜色相同的段,无法判断将两个颜色段合并是否更优。

所以,还需要再加一维。

设 dp[i][j][k] 表示在第 j 段后面出现 k 个与第 j 段颜色相同的木块,消除第 i 段到第 j 段之间的所有木块所能得到的最高得分。


转移方程

考虑转移对于 r 所在的颜色段,有两种情况,可以选择直接消除,或在 r 段前面补上与它颜色相同的木块。

什么意思?

首先,如果直接消除:将 r 段清除后,变成 r−1 段,k=0,再加上清除这一段的得分。

dp[l][r][k] = dp[l][r-1][0] + (len[r]+k) * (len[r]+k)

再考虑第二种情况,在 l 到 r 中找一段与 r 颜色相同的段,设为 x ,将这一段与 r 合并,也就是先清除中间的木块,再将合并的段清除。这时的 k 就变为 len[r]+k 。

dp[l][r][k] = max(dp[l][r][k],dp[x+1][r-1][0]+dp[l][x][len[r]+k])

代码(两种,记忆化搜索和动态规划)

先来看记忆化搜索的。

#include<bits/stdc++.h>
using namespace std;
inline int read(){ //快读不解释int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48) ; ch=getchar();}return x*f;
}
const int M = 210;
int dp[M][M][M],color[M],len[M],a[M]; //如上文的含义
int T,n,tot;
int dfs(int l,int r,int k){if(l==r)return (len[r]+k)*(len[r]+k); //如果搜到一起了,返回此时加的分数if(dp[l][r][k]) return dp[l][r][k]; //这就是记忆化,避免了重复搜索dp[l][r][k] = dfs(l,r-1,0) + (len[r]+k)*(len[r]+k);//上文的转移式1for(register int i(l) ; i<r-1 ; i=-~i){if(color[i] == color[r]){ //这两段颜色相同才能转移dp[l][r][k] = max(dp[l][r][k],dfs(i+1,r-1,0) + dfs(l,i,len[r]+k)); //转移式2}}return dp[l][r][k]; //最后返回此时能得到的最大得分
}
int main(){T=read();for(register int cnt(1) ; cnt<=T ; cnt=-~cnt){memset(dp,0,sizeof(dp));memset(color,0,sizeof(color));memset(len,0,sizeof(len));tot=0; //一定要清零,要不是你错都不知道怎么错的n=read();for(register int i(1) ; i<=n ; i=-~i) a[i] = read();for(register int i(1) ; i<=n ; i=-~i){if(a[i] != a[i-1]){ color[++tot] = a[i]; //这一部分先预处理颜色段数和颜色len[tot]=1;}else len[tot]++;}printf("Case %d: %d\n",cnt,dfs(1,tot,0)); //最后输出就行}return 0;
}

然后放上动态规划的(一定要注意转移顺序

#include<bits/stdc++.h>
using namespace std;
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48) ; ch=getchar();}return x*f;
}
const int M = 210;
int dp[M][M][M],color[M],len[M],a[M],s[M];
int T,n,tot;
int main(){T=read();for(register int cnt(1) ; cnt<=T ; cnt=-~cnt){memset(dp,0,sizeof(dp));memset(color,0,sizeof(color));memset(len,0,sizeof(len));tot=0;n=read();for(register int i(1) ; i<=n ; i=-~i) a[i] = read();for(register int i(1) ; i<=n ; i=-~i){if(a[i] != a[i-1]){ color[++tot] = a[i];len[tot]=1;}else len[tot]++;}for(register int i(1) ; i<=n ; i=-~i) s[i] = s[i-1] + len[i]; //前缀和处理,预处理出前面最多有多少段颜色相同的for(register int l(0) ; l<=n ; l=-~l){for(register int i(1) ; i+l<=n ; i=-~i){ // 注意转移顺序int j = l+i;for(register int k(0) ; k<=s[n]-s[j-1] ; k=-~k){ //k循环到这就行了,一点点优化dp[i][j][k] = dp[i][j-1][0] + (len[j]+k)*(len[j]+k); //转移式1}for(register int k(i) ; k<j ; k=-~k){for(register int h(0) ; h<=s[n]-s[j-1] ; h=-~h){if(color[k] == color[j]){dp[i][j][h] = max(dp[i][j][h],dp[k+1][j-1][0] + dp[i][k][len[j]+h]); //转移式2}}}}}printf("Case %d: %d\n",cnt,dp[1][tot][0]);//颜色段只有tot,不能到n}return 0;
}

YbtOJ 洛谷UVA10559 方块消除相关推荐

  1. YBTOJ洛谷P4074:糖果公园(树上莫队)

    文章目录 解析 update: 代码 所谓树上莫队,就是在树上的莫队 (逃) 传送门 解析 似乎就是树上的这道题 考虑如何转化为序列问题呢? 考虑dfs序 但是又一个问题... 似乎这条链的dfs序不 ...

  2. YBTOJ洛谷P4551:最长异或路径(trie树)

    洛谷传送门 文章目录 题目描述 解析 代码 题目描述 解析 本题关键就在于一点: 若把每个点的深度dep[i]定义为从根到节点边权的异或和 那么i到j的路径异或和可以表示为: dep[i] ^ dep ...

  3. YBTOJ洛谷P3231:消毒(二分图匹配)

    文章目录 题目描述 解析 代码 题目描述 最近在生物实验室工作的小 T 遇到了大麻烦. 由于实验室最近升级的缘故,他的分格实验皿是一个长方体,其尺寸为 a∗b∗ca*b*ca∗b∗c.为了实验的方便, ...

  4. ybtoj洛谷P4406三角形面积并(扫描线)

    解析 暴力求出所有三角形之间的所有交点,提出所有的横坐标. 然后任意两个相邻的横坐标之间的面积都是若干个梯形. 那么就可以求出对于每一个横坐标截得的三角形长度的并的和,然后加在一起乘高除以二即可. 在 ...

  5. ybtoj洛谷P3268:圆的异或并(扫描线)

    解析 很神奇的一道题. 关键条件:任意两个圆无交. 把一个圆分成上下两个圆弧,那么所有圆弧的高度关系不会发生变化. 所以可以开一个 set,维护一个从左往右扫的扫描线,按照当前扫描线的横坐标定义比较符 ...

  6. YBTOJ洛谷P4869:出现位置(线性基)

    解析 关键结论: 若 nnn 个数组成的线性基大小为 SSS,则其子集异或组成的结果有 2S2^S2S 种,且每种结果都有 2n−S2^{n-S}2n−S 种方案. 证明:考虑 n−Sn-Sn−S 个 ...

  7. YBTOJ洛谷P2387: 魔法森林(LCT)

    解析 LCT从板子到算法的入门题吧 有一些不知道的很实用的技巧 把边按a排序从小到大加入边 那么我们只需要维护当前1-n路径上的b的最小值即可 如果这条边两端点本来不连通,就直接link 否则找到路径 ...

  8. YBTOJ洛谷P3292:幸运数字(线性基、点分治/倍增)

    解析 虽然使用三个log的倍增算法艹过去了 但是我们还是来聊聊正解吧 考虑点分治 对于当前的根,dfs求出联通块内每个点到当前根的线性基 一条路径的答案应该在路径出现上第一个成为根的点时统计到 具体来 ...

  9. YBTOJ洛谷P2839:最大中位数(主席树、二分答案)

    遇事不决,二分试试 解析 很好的一道题 真是把主席树玩明白了 一个关于中位数的常用trick: 二分答案mid,把>=mid的看成1,<mid的看成-1,然后看最大子段和是否>=0 ...

最新文章

  1. 使用Docker搭建svn服务器教程
  2. [C++再学习系列] 函数模板和类模板
  3. css动画 animation
  4. 【错误记录】IntelliJ IDEA 中右键点击源码目录选择 New 选项 没有创建 Java Class 选项 ( 将对应的源码目录标记为 Sources 选项 )
  5. Tomcat启动过程中找不到JAVA_HOME解决方法
  6. 洛谷P4145 上帝造题的⑦minutes ②
  7. 前端技术分享:盒模型的概念和文本溢出解决办法
  8. 相册权限_手机相册太乱?1分钟教你快速管理自己的照片,非常好用!
  9. 动态设置html字号,动态设置html的font-size值 (适配文字大小)
  10. Windows -- Qt不能进行调试 -- Unknown debugger type No Engine
  11. ArcGIS中创建数据要素模板,便捷数据采集
  12. 正则表达式修正符的学习
  13. Adobe产品序列号
  14. 714. 买卖股票的最佳时机含手续费-动态规划算法
  15. 征文 | 青出于蓝而胜于蓝 国货之光GBase
  16. 火灾自动报警系统下综合布线施工要素
  17. 明解C语言入门篇_第9章_字符串的基本知识
  18. C语言基本语法——循环篇(三种常见的循环)
  19. 浙大计算机学院app开发,App Inventor - 零基础Android移动应用开发
  20. CAD图纸可以进行哪些格式的转换呢?

热门文章

  1. 构建根文件系统(一)
  2. Universal DEP/ASLR bypass with msvcr71.dll and mona.py
  3. CocosCreator Shader学习(三):放大镜缩小镜效果
  4. 【math】Hiden Markov Model 隐马尔可夫模型了解
  5. 用MSNCartoon制作个性化卡通头像
  6. 能看到打印机共享文件就是不能连接网络打印机
  7. APP按下home键恢复到登录(主界面)
  8. [MySQL进阶]——索引的数据结构
  9. IB学校书单合集请收藏好
  10. 如何把PDF转Word?建议收藏这些方法