[BZOJ2678][Usaco2012 Open]Bookshelf
P.S. 偶然间发现可以用 markdown。。。
[BZOJ2678][Usaco2012 Open]Bookshelf
试题描述
When Farmer John isn't milking cows, stacking haybales, lining up his cows, or building fences, he enjoys sitting down with a good book. Over the years, he has collected \(N\) books (\(1 \leq N \leq 10^5\)), and he wants to build a new set of bookshelves to hold them all. Each book \(i\) has a width \(W(i)\) and height \(H(i)\). The books need to be added to a set of shelves in order; for example, the first shelf should contain books \(1...k\) for some \(k\), the second shelf should start with book \(k+1\), and so on. Each shelf can have a total width of at most \(L\) (\(1 \leq L \leq 10^9\)). The height of a shelf is equal to the height of the tallest book on that shelf, and the height of the entire set of bookshelves is the sum of the heights of all the individual shelves, since they are all stacked vertically. Please help FJ compute the minimum possible height for the entire set of bookshelves. PROBLEM NAME: bookshelf
输入
Line 1: Two space-separated integers: \(N\) and \(L\).
Lines 2..1+N: Line \(i+1\) contains two space-separated integers: \(H(i)\) and \(W(i)\). (\(1 \leq H(i) \leq 10^6\); \(1 \leq W(i) \leq L\)).
输出
- Line 1: The minimum possible total height for the set of bookshelves. SAMPLE
输入示例
5 10 //五本书,每个书架的宽度不超过10
5 7 //第一本书的高度及宽度
9 2
8 5
13 2
3 8
输出示例
21
数据规模及约定
见“试题描述”和“输入”
题解
算法1
这题总体思路肯定是 dp,设 \(f_i\) 表示前 \(i\) 本书所需的最小高度和,则容易得到 \(f_i = min\{ f_j + max\{ H_{j+1}, H_{j+2}, ... , H_i \} | \sum_{k=j+1}^i \leq L \}\)
那么我们只需要考虑从哪个 \(j\) 转移到 \(i\) 就好了。
于是我们可以维护一个 \(H_i\) 下降的单调栈,然后每次计算 \(f_i\) 的时候用前缀和 \(S_i - S_j \leq L\) 的限制二分出 \(j\) 的位置(数组 \(S\) 表示高度的前缀和),然后就是查询单调栈中一段区间的最小值,可以用线段树维护。栈的插入、删除操作都可以当做线段树的点修改。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
#define maxn 100010
#define oo 2147483647
#define ool (1ll << 60)
#define LL long long
int n, hei[maxn], wid[maxn], lim;
LL Sw[maxn];
int S[maxn], mx[maxn], top;
LL f[maxn];
LL minv[maxn<<2];
void update(int o, int l, int r, int p, LL v) {
if(l == r) minv[o] = v;
else {
int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
if(p <= mid) update(lc, l, mid, p, v);
else update(rc, mid + 1, r, p, v);
minv[o] = min(minv[lc], minv[rc]);
}
return ;
}
LL query(int o, int l, int r, int ql, int qr) {
if(l > r) return ool;
if(ql <= l && r <= qr) return minv[o];
int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
LL res = ool;
if(ql <= mid) res = min(res, query(lc, l, mid, ql, qr));
if(qr > mid) res = min(res, query(rc, mid + 1, r, ql, qr));
return res;
}
int main() {
n = read(); lim = read();
for(int i = 1; i <= n; i++) hei[i] = read(), wid[i] = read(), Sw[i] = Sw[i-1] + wid[i];
f[0] = 0; S[0] = 0;
S[top = 1] = mx[1] = 0;
update(1, 1, n + 1, 1, 0);
for(int i = 1; i <= n; i++) {
while(top && hei[i] > mx[top]) top--;
S[++top] = i; mx[top] = hei[i];
// printf("stack: "); for(int j = 1; j <= top; j++) printf("%d%c", S[j], j < top ? ' ' : '\n');
update(1, 1, n + 1, top, f[S[top-1]] + hei[i]);
int l = 1, r = top, pos = lower_bound(Sw, Sw + n + 1, Sw[i] - lim) - Sw;
while(l < r) {
int mid = l + r >> 1;
if(Sw[i] - Sw[S[mid]] > lim) l = mid + 1; else r = mid;
}
f[i] = min(query(1, 1, n + 1, l + 1, top), f[pos] + mx[l]);
// printf("%d %d | %d: %lld\n", l, S[l], i, f[i]);
}
printf("%lld\n", f[n]);
return 0;
}
算法2
还是维护单调栈,我们发现这其实是一个双头队列,偶然在 UOJ 上发现了一个 \(O(n)\) 的做法。
其实就是用两个栈模拟一个双头队列,注意到每个栈的前缀最小值是可以 \(O(1)\) 修改和询问的,所以用这种方法就可能将算法总复杂度降到 \(O(n)\)。
我觉得最妙的地方在于重构,当某个栈空的时候将另一个栈分一半给这个已经空的栈(即暴力重构),复杂度有保证,详见上面链接(读者也不妨自己思考思考)。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
#define maxn 100010
#define oo 2147483647
#define ool (1ll << 60)
#define LL long long
int n, lim, hei[maxn], wid[maxn], lst[maxn]; // lst: last bigger height
LL Sw[maxn];
struct Info {
int pos, mxv; LL val;
Info() {}
Info(int _1, int _2, LL _3): pos(_1), mxv(_2), val(_3) {}
} lft[maxn], rgt[maxn];
int Sl, Sr;
LL mnl[maxn], mnr[maxn];
int rebuild() {
if(!Sl && !Sr) return -1;
if(!Sl) {
int mid = Sr + 1 >> 1;
for(int i = mid; i; i--) lft[++Sl] = rgt[i], mnl[Sl] = min(mnl[Sl-1], lft[Sl].val);
for(int i = mid + 1; i <= Sr; i++) rgt[i-mid] = rgt[i], mnr[i-mid] = min(mnr[i-mid-1], rgt[i-mid].val);
Sr -= mid;
return 0;
}
int mid = Sl + 1 >> 1;
for(int i = mid; i; i--) rgt[++Sr] = lft[i], mnr[Sr] = min(mnr[Sr-1], rgt[Sr].val);
for(int i = mid + 1; i <= Sl; i++) lft[i-mid] = lft[i], mnl[i-mid] = min(mnl[i-mid-1], lft[i-mid].val);
Sl -= mid;
return 0;
}
int q[maxn], hd, tl;
LL f[maxn];
int main() {
n = read(); lim = read();
for(int i = 1; i <= n; i++) hei[i] = read(), wid[i] = read(), Sw[i] = Sw[i-1] + wid[i];
hei[0] = oo;
for(int i = 1; i <= n; i++) {
lst[i] = i - 1;
while(hei[lst[i]] <= hei[i]) lst[i] = lst[lst[i]];
}
mnl[0] = mnr[0] = ool;
rgt[++Sr] = Info(lst[1], hei[1], hei[1]);
mnr[1] = f[1] = hei[1];
q[hd = tl = 1] = 1;
int lft_edge = 0;
for(int i = 2; i <= n; i++) {
while(1) {
if(!Sr && rebuild()) break;
if(rgt[Sr].mxv > hei[i]) break;
Sr--;
}
rgt[++Sr] = Info(lst[i], hei[i], f[lst[i]] + hei[i]);
mnr[Sr] = min(mnr[Sr-1], rgt[Sr].val);
while(1) {
if(!Sl && rebuild()) break;
if(Sw[i] - Sw[lft[Sl].pos] <= lim) break;
Sl--;
}
while(Sw[i] - Sw[lft_edge] > lim) lft_edge++;
while(hd <= tl && hei[i] >= hei[q[tl]]) tl--; q[++tl] = i;
while(lft_edge > q[hd]) hd++;
f[i] = min(min(mnl[Sl], mnr[Sr]), f[lft_edge] + hei[q[hd]]);
// printf("f[%d] = %lld\n", i, f[i]);
}
printf("%lld\n", f[n]);
return 0;
}
P.S. markdown 好难用。。。
[BZOJ2678][Usaco2012 Open]Bookshelf的更多相关文章
- [USACO2012 OPEN] Bookshelf
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=2678 [算法] 首先不难想到如下DP : 记f[i]表示前i本书的高度和最小值 显然 ...
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- bookshelf
nodejs mysql ORM 比node-mysql好用多了. bookshelf 支持restful功能,用到的时候研究下:https://www.sitepoint.com/getting-s ...
- POJ3628 Bookshelf 2(01背包+dfs)
Bookshelf 2 Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 8745 Accepted: 3974 Descr ...
- Bookshelf 2
Bookshelf 2 Time Limit:1000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u Submit ...
- POJ 3628 Bookshelf 2(01背包)
Bookshelf 2 Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9488 Accepted: 4311 Descr ...
- 动态规划(状态压缩):BZOJ 2621 [Usaco2012 Mar]Cows in a Skyscraper
2621: [Usaco2012 Mar]Cows in a Skyscraper Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 303 Sol ...
- BZOJ3016: [Usaco2012 Nov]Clumsy Cows
3016: [Usaco2012 Nov]Clumsy Cows Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 71 Solved: 52[Submi ...
- BZOJ 3011: [Usaco2012 Dec]Running Away From the Barn( dfs序 + 主席树 )
子树操作, dfs序即可.然后计算<=L就直接在可持久化线段树上查询 -------------------------------------------------------------- ...
随机推荐
- Ubuntu18.04如何从英文界面更改为中文界面
本文介绍如何将Ubuntu18.04安装后的英文界面,更改为中文界面,即系统语言由英文改为简体中文.注意,与安装中文输入法不同,两者也没有冲突. 首先进入设置(Setting),选择区域和语言(Reg ...
- Ball Coloring
6552: Ball Coloring 时间限制: 1 Sec 内存限制: 128 MB提交: 13 解决: 7[提交][状态][讨论版][命题人:admin] 题目描述 There are N ...
- java基础—java读取properties文件
一.java读取properties文件总结 在java项目中,操作properties文件是经常要做的,因为很多的配置信息都会写在properties文件中,这里主要是总结使用getResource ...
- 虚拟机设置NAT
需要开启虚拟机网络相关服务, 安装虚拟网卡, 还有必须安装 VMware Tools VMware虚拟机下实现NAT方式上网1. 把你的虚拟网卡VMnet8设置为自动获得IP.自动获得DNS服务器,启 ...
- RabbitMQ Server的安装、配置及常用命令
首先需要安装Erlang环境: http://www.rabbitmq.com/server.html 下载RabbitMQ Server的windows安装包并安装到D盘下: http://www. ...
- 机器学习十大常用算法(CITE 不会停的蜗牛 ) interesting
算法如下: 决策树 随机森林算法 逻辑回归 SVM 朴素贝叶斯 K最近邻算法 K均值算法 Adaboost 算法 神经网络 马尔可夫 1. 决策树 根据一些 feature 进行分类,每个节点提一个问 ...
- 《effective c++》问题总结
04 确定对象被使用前已先被初始化 1.static/heap/stack对象 2.trivial对象 3.模板隐式具现化 implicit template instantiations 4.Sin ...
- 51nod——1391 01串(字符串、前缀和)
好像这题是4级题下放2级? 预处理:求每个位置 x 左区间 [ 0 , x ] 中 1 比 0 多的数量和右区间 ( x , n - 1 ] 中 0 比 1 多的数量(少就是负的).相当于求两个前缀和 ...
- python--以1-31的数字作为结尾的列表?论英文好的重要性!
一.python基础教程第2板(修订版)[代码清单2-1]中有一段要求打印‘以1-31的数字作为结尾的列表’ 截取代码示例:endings =['st','nd','rd'] +17*['th'] + ...
- 多线程辅助类之CountDownLatch(三)
CountDownLatch信号灯是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待.它可以实现多线程的同步互斥功能,和wait和notify方法实现功能类似,具体 ...