【题解】【THUSC 2016】成绩单 LOJ 2292 区间dp
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的更多相关文章
- loj 1031(区间dp+记忆化搜索)
题目链接:http://lightoj.com/volume_showproblem.php?problem=1031 思路:dp[i][j]表示从区间i-j中能取得的最大值,然后就是枚举分割点了. ...
- BZOJ 1996: [Hnoi2010]chorus 合唱队(区间dp)
题目: https://www.lydsy.com/JudgeOnline/problem.php?id=1996 题解: 这题刚拿到手的时候一脸懵逼qwq,经过思考与分析(看题解),发现是一道区间d ...
- 「USACO16OPEN」「LuoguP3146」248(区间dp
题目描述 Bessie likes downloading games to play on her cell phone, even though she doesfind the small to ...
- SPOJ MIXTURES 区间dp
Harry Potter has n mixtures in front of him, arranged in a row. Each mixture has one of 100 differen ...
- UVA1630 Folding 区间DP
Folding Description Bill is trying to compactly represent sequences of capital alphabetic characte ...
- LOJ 2292 「THUSC 2016」成绩单——区间DP
题目:https://loj.ac/problem/2292 直接 DP 很难做,主要是有那种 “一个区间内部有很多个别的区间” 的情况. 自己想了一番枚举 max-min 的最大限制,然后在该基础上 ...
- loj 2292「THUSC 2016」成绩单
loj 看着就很区间dp,所以考虑求\(f_{i,j}\)表示区间\([i,j]\)的答案.注意到贡献答案的方式是每次选一个连续段,拿走后剩下的段拼起来继续段,所以转移就考虑从最后一次选的方法转移过来 ...
- 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) ...
- 【bzoj4897】[Thu Summer Camp2016]成绩单 区间dp
题目描述 给你一个数列,每次你可以选择连续的一段,付出 $a+b\times 极差^2$ 的代价将其删去,剩余部分拼到一起成为新的数列继续进行此操作.求将原序列全部删去需要的最小总代价是多少. 输入 ...
随机推荐
- console.log() 替代函数
var log = console.log.bind(console); log('d')
- Scrum Meeting 7 -2014.11.13
之前srcum没写好是我的错.以后会每天更新的. 老师反映之前项目小组从pdf中提取作者效果不好,我们讨论决定进行一定的优化.在整合测试的同时开始服务器程序部署. Member Today’s tas ...
- 2-Tenth Scrum Meeting20151210
任务分配 闫昊: 今日完成:请假.(编译) 明日任务:参加会议讨论,安排任务分工. 唐彬: 今日完成:请假.(编译) 明日任务:参加会议讨论,安排任务分工. 史烨轩: 今日完成:请假.(编译) 明日任 ...
- Linux下查看cpu使用率
top命令 是Linux下常用的性能 分析工具 ,能够实时显示系统 中各个进程的资源占用状况,类似于Windows的任务管理 器.下面详细介绍它的使用方法. top - 02:53:32 up 16 ...
- Javascript toString()、toLocaleString()、valueOf()三个方法的区别
Array.Boolean.Date.Number等对象都具有toString().toLocaleString().valueOf()三个方法,那这三个方法有什么区别??? 一.JS Array 例 ...
- bata4
目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员:恺琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示组 ...
- MIT挑战(如何在12个月内自学完成MIT计算机科学的33门课程|内附MIT公开课程资源和学习顺序
译者注:本文译自Scott H. Young的博客,Scott拥有超强的学习能力,曾在12个月内自学完成麻省理工学院计算机科学的33门课程.本文就是他个人对于这次MIT挑战的介绍和总结. 版权声明:本 ...
- week4d:个人博客作业
7,程序结果的显示 1,界面 2,选第一选项. 3,输入3个数后. 4,选择第一个. 5,输入第4个数字. 6,再次进行一轮游戏. 7,选择是否要看历史记录. 8,进入下一轮游戏. 9,开始第二轮数字 ...
- vue 如何使用scss (转载)
创建一个基于 webpack 模板的新项目 全局安装 vue-cli $ npm install --global vue-cli 创建一个基于 webpack 模板的新项目 $ vue init w ...
- 个人阅读&个人总结
个人阅读作业+总结 助教推荐的那些文章都是软件工程上的经典文章,阅读后感受到软件工程本身的深度,之前学习的软件工程都只是皮毛之中的皮毛而已.随着软件规模的越来越庞大,软件工程已经成为了软件开发中的必备 ...