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. 更换 CentOS 7 的下载源为阿里云

    http://blog.csdn.net/realghost/article/details/45949759

  2. TeamWork#3,Week5,Scrum Meeting 11.15

    经过最近一段时间的努力,我们调整了爬虫结构,并在继续进行爬虫开发,马上可以进行新爬虫与服务器连接的测试. 成员 已完成 待完成 彭林江 基本完成爬虫结构调整 新爬虫与服务器连接 郝倩 基本完成爬虫结构 ...

  3. 2-Seventh Scrum Meeting20151207

    任务分配 闫昊: 今日完成:完成数据库设计. 明日任务:和唐彬讨论接口如何在android实现. 唐彬: 今日完成:读了IOS讨论区后台接口. 明日任务:和闫昊讨论接口如何在android实现. 史烨 ...

  4. Buaaclubs的NABC与发布

    NEED: 本项目主要目的是实现一个社团学生公共平台,平台的宗旨是为学生提供信息,为社团提供服务,在社团和学生之间建立联系.经过调查,我们发现了用户的以下需求: 需求一:社团发布信息,同学获知信息 这 ...

  5. JAVA第一次实验 ——实验楼

    北京电子科技学院(BESTI) 实     验    报     告 课程:Java程序设计 班级:1352  姓名:潘俊洋  学号:20135230 成绩:             指导教师:娄嘉鹏 ...

  6. 2017-2018-2 1723 『Java程序设计』课程 结对编程练习_四则运算

    一.结对对象 姓名:侯泽洋 学号:20172308 担任角色:驾驶员(侯泽洋) 伙伴第一周博客地址 二.本周内容 1.程序需求 (1).自动生成题目 可独立使用(能实现自己编写测试类单独生成题目的功能 ...

  7. sqlDataAdapter和SqlCommand的区别

    因为DataSet是离线的,所以SqlDataAdapter这个对象是连接DataSet和数据库的桥梁,所有对DataSet的操作(填充,更新等)都要通过他 ado.net数据访问有两种方式: 1.离 ...

  8. UVA - 11021 Tribles 概率dp

    题目链接: http://vjudge.net/problem/UVA-11021 Tribles Time Limit: 3000MS 题意 有k只麻球,每只活一天就会死亡,临死之前可能会出生一些新 ...

  9. 路由器配置及IP设置及ping命令使用

    OSI的七层协议体系结构: 物理层.数据链路层.网络层.运输层.会话层.表示层.应用层 TCP/IP是一个四层的体系结构: 网络接口层.网际层(互联网层)(IP或ARP或ICMP).运输层(TCP或U ...

  10. OSG学习:裁剪变换(1)

    在OSG中,默认了6个裁剪平面以去除没有必要显示的物体.也可以自己定义其他的裁剪平面来确定裁剪. osg::ClipPlane类继承自osg::StateAttribute类,封装了OpenGL中的g ...