Prelude

快THUWC了,所以补一下以前的题。

真的是一道神题啊,网上的题解没几篇,而且还都看不懂,我做了一天才做出来。

传送到LOJ:(>人<;)


Solution

直接切入正题。

我们考虑区间dp,第一件事是离散化。

然后用\(g(i,j)\)表示消除完闭区间\([i,j]\)的最小费用。

然后呢?怎么转移?exm???

这时候会有一个非常自然的想法。

计算\(g(i,j)\)的时候,我们枚举两个数\(l,r\),然后保留下值在闭区间\([l,r]\)之内的所有数,先消除掉其他的数字,就只剩\([l,r]\)之内的数字了,再一次性消除掉她们。

时间复杂度\(O(n^5)\),但是显然是错的。

错在哪里呢?大概是错在下面这种情况,我懒得构造具体的反例了。

对于一组数字\(abcabca\),我们可以先消除掉中间的\(a\),再消除掉\(bcbc\),最后再消除掉\(aa\),在我们的dp里面似乎并没有考虑到这种情况。

因为\(aa\)是最后消除掉的,因此如果我们选择保留\(a\)的话,会保留下来所有的\(a\)。

我们太仁慈了,保留下来了\([l,r]\)之间的所有的数字,其实不一定要保留所有数字。

怎么办呢?

脑洞大开!

我们用\(f(i, j, l, r)\)表示,消除完在闭区间\([i,j]\)之内的,除了值在\([l,r]\)之间的所有数字。

注意,在\([l,r]\)之间的数字,可以消除,也可以不消除。

然后显然有这个东西:

$\Large g(i, j) = \min f(i, j, l, r)$
实际上就是枚举$l,r$嘛。
然后我们考虑$f(i, j, l, r)$如何转移。
当闭区间$[i,j]$内元素全部在$[l,r]$之间的时候,显然$f(i, j, l, r)=0$。
当闭区间$[i,j]$内元素全部不在$[l,r]$之间的时候,显然$f(i, j, l, r)=g(i, j)$。
$f(i, j, l, r)=g(i, j)$似乎构成了循环依赖?
那么,我们枚举$l,r$的时候,必须保证区间$[i,j]$内存在至少一个数字在$[l,r]$内,这样就不会有循环依赖了。
解决了$f(i, j, l, r)$的边界问题,接下来看如何转移。
像普通的区间dp一样,我们枚举区间的分裂点$k$,然后把区间$[i,j]$分裂成$[i,k]$和$[k+1,j]$两部分,递归做下去。
有式子:
$\Large f(i, j, l, r) = \min f(i, k, l, r) + f(k+1, j, l, r)$
感受一下,感觉似乎是能处理各种情况的?
但是实际上和刚刚的做法没有任何区别。
因为对于状态$f(i, j, l, r)$,我们仍然保留了$[l,r]$之间的所有数字,仍然是那么的仁慈。
我们需要加一种暴力斩掉所有数字的情况。
有式子:
$\Large f(i, j, l, r) = \min g(i, k) + f(k+1, j, l, r)$
仔细感受一下,这两个$f(i, j, l, r)$的转移式结合起来之后,就可以处理掉所有情况了!
时间复杂度仍然是$O(n^5)$。
实现采用记忆化搜索,效果棒棒哒~
真是一道神题啊。。。


Code

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <iostream> using namespace std;
const int N = 52;
const int W = 1010;
const int INF = 0x3f3f3f3f;
int _w; int bmin( int &a, int b ) {
return a = b < a ? b : a;
} int n, a, b, w[N];
int vis[W], num[N], m;
int f[N][N][N][N], g[N][N];
int F( int, int, int, int );
int G( int, int ); void discrete() {
for( int i = 1; i <= n; ++i )
vis[w[i]] = 1;
m = 1;
for( int i = 1; i < W; ++i )
if( vis[i] )
vis[i] = m, num[m++] = i;
--m;
for( int i = 1; i <= n; ++i )
w[i] = vis[w[i]];
} bool contain( int i, int j, int l, int r ) {
for( int p = i; p <= j; ++p )
if( w[p] >= l && w[p] <= r )
return true;
return false;
} bool all( int i, int j, int l, int r ) {
for( int p = i; p <= j; ++p )
if( w[p] < l || w[p] > r )
return false;
return true;
} int F( int i, int j, int l, int r ) {
int &now = f[i][j][l][r];
if( now != -1 ) return now;
if( all(i, j, l, r) ) return now = 0;
if( !contain(i, j, l, r) ) return now = G(i, j);
now = INF;
for( int k = i; k < j; ++k ) {
bmin( now, F(i, k, l, r) + F(k+1, j, l, r) );
bmin( now, G(i, k) + F(k+1, j, l, r) );
}
// printf( "f[%d][%d][%d][%d] = %d\n", i, j, l, r, now );
return now;
} int G( int i, int j ) {
int &now = g[i][j];
if( now != -1 ) return now;
now = INF;
for( int l = 1; l <= m; ++l )
for( int r = l; r <= m; ++r )
if( contain(i, j, l, r) ) {
int u = num[l], v = num[r];
bmin( now, F(i, j, l, r) + (v-u)*(v-u)*b + a );
}
// printf( "g[%d][%d] = %d\n", i, j, now );
return now;
} int main() {
cin >> n >> a >> b;
for( int i = 1; i <= n; ++i )
cin >> w[i];
discrete();
memset(f, -1, sizeof f);
memset(g, -1, sizeof g);
printf( "%d\n", G(1, n) );
return 0;
}

【题解】【THUSC 2016】成绩单 LOJ 2292 区间dp的更多相关文章

  1. loj 1031(区间dp+记忆化搜索)

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1031 思路:dp[i][j]表示从区间i-j中能取得的最大值,然后就是枚举分割点了. ...

  2. BZOJ 1996: [Hnoi2010]chorus 合唱队(区间dp)

    题目: https://www.lydsy.com/JudgeOnline/problem.php?id=1996 题解: 这题刚拿到手的时候一脸懵逼qwq,经过思考与分析(看题解),发现是一道区间d ...

  3. 「USACO16OPEN」「LuoguP3146」248(区间dp

    题目描述 Bessie likes downloading games to play on her cell phone, even though she doesfind the small to ...

  4. SPOJ MIXTURES 区间dp

    Harry Potter has n mixtures in front of him, arranged in a row. Each mixture has one of 100 differen ...

  5. UVA1630 Folding 区间DP

    Folding Description   Bill is trying to compactly represent sequences of capital alphabetic characte ...

  6. LOJ 2292 「THUSC 2016」成绩单——区间DP

    题目:https://loj.ac/problem/2292 直接 DP 很难做,主要是有那种 “一个区间内部有很多个别的区间” 的情况. 自己想了一番枚举 max-min 的最大限制,然后在该基础上 ...

  7. loj 2292「THUSC 2016」成绩单

    loj 看着就很区间dp,所以考虑求\(f_{i,j}\)表示区间\([i,j]\)的答案.注意到贡献答案的方式是每次选一个连续段,拿走后剩下的段拼起来继续段,所以转移就考虑从最后一次选的方法转移过来 ...

  8. 2016 ACM/ICPC Asia Regional Shenyang Online 1009/HDU 5900 区间dp

    QSC and Master Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) ...

  9. 【bzoj4897】[Thu Summer Camp2016]成绩单 区间dp

    题目描述 给你一个数列,每次你可以选择连续的一段,付出 $a+b\times 极差^2$ 的代价将其删去,剩余部分拼到一起成为新的数列继续进行此操作.求将原序列全部删去需要的最小总代价是多少. 输入 ...

随机推荐

  1. python循环综合运用

    循环很重要,计算机很蠢,唯一的优势就是按照指令不停的执行,所以决定在说一下. break语句,用在循环体中,迫使循环立即终止,即跳出所在循环体,继续执行循环体后面的语句. sum=0 i=1 whil ...

  2. Linux下lshw,lsscsi,lscpu,lsusb,lsblk硬件查看命令

    Linux下lshw,lsscsi,lscpu,lsusb,lsblk硬件查看命令 2016-12-14 何敏杰 1条评论 544次浏览   注意:如有提示命令找不到command not found ...

  3. Scrum Meeting 11.04

    成员 今日任务 明日计划 用时 徐越 学习Fragment相关知识,代码移植 代码移植 4h 赵庶宏 selvet移植,服务器配置,编写数据库 服务器配置,代码移植 4h 薄霖 学习安卓界面设计数据库 ...

  4. 第二阶段Sprint2

    昨天:讨论冲刺阶段,目标,任务认领 今天:查看资料,开始视频录制部分的代码实现 遇到的问题:不能暂停后继续录制,只能直接结束

  5. WebGL学习笔记二

    前一章就是第二章主要学的是通过WebGL实现先是在webGL内赋值,但是不实用后来通过定义attribute和uniform存储限定符来将javascript中的数据传到webGL中,大致的流程是1. ...

  6. css3学习笔记一

    首先界面是二维的但也可以有三维的效果.先了解浏览器兼容性问题,火狐加前缀(-moz-)IE加(-MF-)谷歌加(-webkit),简单介绍css3的几个属性. 对于背景来说如果是单纯着一种颜色可以会单 ...

  7. 团队作业之四则运算GUI展示

    一.项目Coding.net原码仓库地址:https://git.coding.net/caoying/Teamwork.git 队员: 卢琪:2016011986 曹滢:2016012102 二.P ...

  8. CefSharp,Winform程序中加载web网页

    源码地址:https://github.com/cefsharp/CefSharp 开源相关:https://github.com/cefsharp/CefSharp/tree/master/CefS ...

  9. (三)使用Jmeter模拟300个用户登录

    1.首先在系统中创建300个用户(在这里使用 pl/sql 进行循环创建): 代码如下: --先对原先的表进行备份 :CREATE TABLE sys_user_bak AS SELECT * FRO ...

  10. js中的php rand函数

    //文件rand.js function MyRand(min, max){ this.min = min; this.max = max; } MyRand.prototype.getRand = ...