博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
『Blocks 区间dp』
阅读量:4678 次
发布时间:2019-06-09

本文共 2316 字,大约阅读时间需要 7 分钟。


Blocks

Description

Some of you may have played a game called 'Blocks'. There are n blocks in a row, each box has a color. Here is an example: Gold, Silver, Silver, Silver, Silver, Bronze, Bronze, Bronze, Gold. The corresponding picture will be as shown below:

5cfe457bce4d064446.jpg

If some adjacent boxes are all of the same color, and both the box to its left(if it exists) and its right(if it exists) are of some other color, we call it a 'box segment'. There are 4 box segments. That is: gold, silver, bronze, gold. There are 1, 4, 3, 1 box(es) in the segments respectively.

Every time, you can click a box, then the whole segment containing that box DISAPPEARS. If that segment is composed of k boxes, you will get kk points. for example, if you click on a silver box, the silver segment disappears, you got 44=16 points.

Now let's look at the picture below:

5cfe45917281883900.jpg

The first one is OPTIMAL.

Find the highest score you can get, given an initial state of this game.

题意:通过点击某一颜色消除相邻的所有的这种颜色,得分为len*len,求最大分

Input Format

第一行为一个整数 N。

第二行为 A1,A2,…,AN。

Output Format

一行一个整数,代表最大价值。

Sample Input

91 2 2 2 2 3 3 3 1

Sample Output

29

解析

这种区间操作类的最优解问题显然是区间\(dp\),不过这道题的状态有点棘手。

对于一次消除操作,可能会带来左右两边原本不相邻的部分合并带来的影响,所以通常来说的状态是不行了。我们考虑设计一种状态能够记录这种合并带来的影响:设\(f[l][r][k]\)代表区间消除\([l,r]\),序列后面通过消除操作使得有\(k\)个颜色为\(a[r]\)的块跟在区间\([l,r]\)后面的最大得分。

考虑转移,显然,我们可以直接将后面跟着的\(k\)个块和第\(r\)个块连在一起消掉,这是一种转移方式。还有就是我们可以在区间\([l,r-1]\)中枚举一个颜色与\(a[r]\)相同的点\(i\),然后将区间\([i+1,r-1]\)作为一个子问题直接消去,这样就使得\(a[r]\)加入后面跟着的\(k\)个块中,\(i\)成为右端点,利用这个状态转移即可。

至于如何枚举区间内和\(a[r]\)颜色相同的点呢?这是可以预处理直接向前查找的。

\(Code:\)

#include
using namespace std;const int N = 220;int n,a[N],pre[N],last[N];int f[N][N][N];inline void input(void){ scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[i]);}inline void init(void){ for (int i=1;i<=n;i++) { pre[i] = last[a[i]]; last[a[i]] = i; }}inline int dp(int l,int r,int k){ if ( l > r ) return 0; if ( f[l][r][k] ) return f[l][r][k]; f[l][r][k] = dp( l , r-1 , 0 ) + (k+1) * (k+1); for (int i=pre[r];i>=l;i=pre[i]) f[l][r][k] = max( f[l][r][k] , dp( l , i , k+1 ) + dp( i+1 , r-1 , 0 ) ); return f[l][r][k];}int main(void){ input(); init(); memset( f , 0 , sizeof f ); dp( 1 , n , 0 ); printf("%d\n",f[1][n][0]); return 0;}

转载于:https://www.cnblogs.com/Parsnip/p/10999917.html

你可能感兴趣的文章
格网与四叉树索引
查看>>
多张照片拍摄、图片浏览
查看>>
html(5) css
查看>>
Azure Web连接到Azure MySql Db
查看>>
Linux shell 命令判断执行语法 ; , && , ||
查看>>
vim代码格式化插件clang-format
查看>>
What does the dot after dollar sign mean in jQuery when declaring variables?
查看>>
windows registry
查看>>
jquery 动画总结(主要指效果函数)
查看>>
leetcode-17-电话号码的字母组合’
查看>>
Flume 示例
查看>>
Designing for Performance
查看>>
HTML属性的应用
查看>>
HEAP CORRUPTION DETECTED
查看>>
Android URI简单介绍
查看>>
蒙板 模态对话框
查看>>
pythong中的全局变量的调用和嵌套函数中变量的使用
查看>>
【POJ - 3009】Curling 2.0 (dfs+回溯)
查看>>
Windows下载安装良心教程
查看>>
浅析商业银行“业务连续性管理体系”的构建
查看>>