洛谷P1848 书架
好,我一直以为书架是splay,然后发现还有个优化DP的书架。妃的书架
蓝书和PPT上面都讲了,应该比较经典吧。
题意:
有n个物品,每个都有宽,高。
把它们分成若干段,使得每段的最大值的总和最小。且每段的总宽度不超过L。
n <= 100000
解:
首先有个很显然的DP是f[i] = min(f[j] + max(j + 1, i)), sum[i] - sum[j] <= L
然后如何优化呢?因为有max函数(非线性)所以难以单调队列。把决策打出来发现不单调。无计可施???
发现当i固定的时候,max(j + 1, i)是一段一段单减的。这样相当于能确定状态转移方程中的后者。
再看前者,f[j]这个东西,其实是单调不减的。证明:把f[j - 1]按照f[j]的方式划分即可<=f[j]。
怎么利用呢?朴素的想法是把每一个数前面最大的数用单调栈求出来,记为to[]数组。
那么每次转移的时候跳to[]即可。可以发现在区间(to[i], i)之间的转移都不优于to[i]。
这里忽视了一个小问题,有个宽度限制在这里。我的解决办法是用pos记录最早的一个能够转移过来的位置。pos的维护显然是线性的。
这个好想好写的东西最坏复杂度还是n²,递增序列就能卡掉,然而交上去有90分......
来考虑正解。我们能不能每次不跳to[]链,而是更快的求出最小值来转移呢?
很容易(困难)想到用堆维护。对于失效的转移用延迟删除法。
问题就只剩如何判断转移失效了。
如果转移的j < pos,显然不行。此外,如果j不在以i开头的to链上,也是不行的。
有个朴素的想法是用数组维护是否在to链上,即每次把i前面比i小的舍去,但是又会被递增卡成n²。
仔细思考,发现以i开头的to链就是单调栈在处理到i时的栈内元素。
于是我们一边DP一边维护单调栈,只需判断j是在否在栈中即可。
至此,时间复杂度优化为nlogn,可以通过此题。
记得开long long
#include <cstdio>
#include <algorithm>
#include <queue>
#define mp std::make_pair typedef long long LL;
const int N = ; LL f[N], sum[N];
int st[N][], pow[N], n, to[N], p[N], top;
bool in_stk[N];
std::priority_queue<std::pair<LL, int> > Q; inline void STinit() {
int j = , lm = ;
while(( << lm) <= n) {
while(j < ( << (lm + )) && j <= n) {
pow[j] = lm;
j++;
}
lm++;
}
for(int j = ; j < lm; j++) {
for(int i = ; i + ( << j) - <= n; i++) {
st[i][j] = std::max(st[i][j - ], st[i + ( << (j - ))][j - ]);
}
}
return;
} inline int getmax(int l, int r) {
int t = pow[r - l + ];
return std::max(st[l][t], st[r - ( << t) + ][t]);
} int main() {
int L;
scanf("%d%d", &n, &L);
for(int i = ; i <= n; i++) {
scanf("%d%lld", &st[i][], &sum[i]);
sum[i] += sum[i - ];
f[i] = 1ll << ;
} STinit();
st[][] = 0x7f7f7f7f;
to[] = -; int pos = ;
for(int i = ; i <= n; i++) {
while(st[i][] >= st[p[top]][]) {
in_stk[p[top]] = ;
top--;
}
to[i] = p[top];
p[++top] = i;
in_stk[i] = ; Q.push(mp(- * (f[to[i]] + getmax(to[i] + , i)), i)); while(sum[i] - sum[pos] > L) {
pos++;
}
while((!Q.empty()) && (to[Q.top().second] < pos || (!in_stk[Q.top().second]))) {
Q.pop();
}
if(!Q.empty()) {
f[i] = - * Q.top().first;
}
f[i] = std::min(f[i], f[pos] + getmax(pos + , i));
}
/*for(int i = 1; i <= n; i++) {
printf("%lld ", f[i]);
}*/
printf("%lld", f[n]);
return ;
}
AC代码
但是还有很多可以改进的地方。
比如to这个数组可否舍去?ST表可否舍去?我是懒得优化了T_T
洛谷P1848 书架的更多相关文章
- 洛谷P3850 书架
题目描述 Knuth先生家里有个精致的书架,书架上有N本书,如今他想学到更多的知识,于是又买来了M本不同的新书.现在他要把新买的书依次插入到书架中,他已经把每本书要插入的位置标记好了,并且相应的将它们 ...
- 洛谷P2468 SDOI 2010 粟粟的书架
题意:给你一个矩形书架,每个点是这本书的页数,每次询问(x1,y1)(x2,y2)这个小矩形里最少需要取几本书使得页数和等于Hi. 题解:小数据二位前缀和预处理+二分答案,大数据一行所以用主席树做,感 ...
- [洛谷P2596] [ZJOI2006]书架
洛谷题目链接:书架 题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后 ...
- 洛谷P2468 [SDOI2010]粟粟的书架
来了来了,随便拽一道题写题解[大雾] 最近发现自己基础奇差于是开始复习之前学过的东西,正好主席树我几乎完全没学会,然后打开洛谷试炼场… 发现了这么一道二合一的题. 这道题其实分成两个部分,前50%是一 ...
- 洛谷P2464 [SDOJ2008]郁闷的小J
洛谷P2464 [SDOJ2008]郁闷的小J 题目描述 小J是国家图书馆的一位图书管理员,他的工作是管理一个巨大的书架.虽然他很能吃苦耐劳,但是由于这个书架十分巨大,所以他的工作效率总是很低,以致他 ...
- 洛谷 P1103 书本整理(动规)
洛谷 P1103 书本整理 题目描述 Frank是一个非常喜爱整洁的人.他有一大堆书和一个书架,想要把书放在书架上.书架可以放下所有的书,所以Frank首先将书按高度顺序排列在书架上.但是Frank发 ...
- 洛谷1640 bzoj1854游戏 匈牙利就是又短又快
bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...
- 洛谷P1352 codevs1380 没有上司的舞会——S.B.S.
没有上司的舞会 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description Ural大学有N个职员,编号为1~N.他们有 ...
- 洛谷P1108 低价购买[DP | LIS方案数]
题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...
随机推荐
- 【学亮IT手记】Java 8新特性实例介绍
java8,也称为jdk1.8,于2014.03.18日发布,它支持函数式编程,新的js引擎,新的日期API,新的Stream Api等. 我们主要讨论以下几个新特性: ①Lambda表达式. 允许把 ...
- python 三目运算符
格式: true_res if condition else false_res Meto 1: Meto 2: >>> x = 2 >>> x+1 if x!=1 ...
- debug方法
debug as -> spring boot->开始了 可以添加 ,, 来进行向下步骤:使用其他方法(在方法内打点) 一步步F6就可以了
- LODOP 获取打印设计代码不带INIT初始化语句
前面的博文生成JS代码模版和文档式模版,生成的是带初始化语句的模版,如果想要打印多个,可以循环多个任务,什么是一个任务,可查看本博客相关博文:Lodop打印语句最基本结构介绍(什么是一个任务)一个任务 ...
- Winform实现多线程异步更新UI(进度及状态信息)
引言 在进行Winform程序开发需要进行大量的数据的读写操作的时候,往往会需要一定的时间,然在这个时间段里面,界面ui得不到更新,导致在用户看来界面处于假死的状态,造成了不好的用户体验.所以在大量数 ...
- gevent监测单线程下的io进行切换
from gevent import monkey;monkey.patch_all() import gevent import time def eat(name): print('%s eat ...
- 【python练习题】程序12
#题目:判断101-200之间有多少个素数,并输出所有素数. #判断素数的方法:用一个数分别去除2到sqrt(这个数),如果能被整除,则表明此数不是素数,反之是素数. from math import ...
- Nintex Workflow Get Attachment link
不多解释,直接上图,操作简单
- zabbix在ubuntu16.04上的安装
开始安装 zabbix具体安装可以参考官方文档写的很详细,令人高兴的是现在有了中文的版本的翻译,这里简要说下. 上篇文章我写了在ubuntu14.04上安装zabbix,见这里http://www.c ...
- HDU4349-Xiao Ming's Hope-找规律
打表输出前100之后,找到规律. 不过正确规律是1<<(二进制中1的个数). #include <cstdio> #include <algorithm> usin ...