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

本文共 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

你可能感兴趣的文章
python模块详解 XML
查看>>
微信公众平台开发文档 获取关注者列表
查看>>
[若有所悟]我看日式外包项目软件过程
查看>>
java 学习笔记-数组(三)
查看>>
jQuery打印Html页面自动分页
查看>>
获取css规则
查看>>
vue的基础使用
查看>>
UIAlertView添加textField
查看>>
Keystone中间件WSGI环境变量总结
查看>>
通过phoenix在hbase上创建二级索引,Secondary Indexing
查看>>
SpringMVC静态资源拦截的问题
查看>>
maven jetty运行时,js无法保存
查看>>
动态规划------平均切分数组之和为两部分
查看>>
python中的I/O
查看>>
面向对象数据访问添加数据和删除数据
查看>>
关于链表的基本操作
查看>>
移动端UI设计的经验总结
查看>>
中间件
查看>>
二分查找
查看>>
软件流程图的画法(函数)
查看>>