[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就直接在可持久化线段树上查询 -------------------------------------------------------------- ...
随机推荐
- [dp][uestc oj]J - 男神的约会
J - 男神的约会 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Submit ...
- 在ProgressBar控件中显示进度百分比
实现效果: 知识运用: ProgressBar控件的Value属性 //控件的当前值 Maximum属性 //ProgressBar正在使用的范围的上限 PerformStep方法 //按照Step属 ...
- CentOS7-samba文件共享服务
简介: Samba,是在Unix上实现SMB(Server Message Block)的一个工具套件.而SMB通常是windows用来实现共享的,包括文件和打印机等.而Unix上装上SMB,则使得U ...
- CPP-网络/通信:用CMarkup类操纵XML
首先到http://www.firstobject.com/下载CMarkup教学版,解压后里面是一个DEMO,将Markup.h .cpp拷贝并添加到工程中,第一次编译可能会出现预编译错误,解决 ...
- React脚手架less的安装
最近在用react.js 结合蚂蚁金服的 Ant Design Mobile 做一个单页面的应用程序,遇到了一个很棘手的问题——那就是 react脚手架不支持less,看了不少优秀博主如何在react ...
- java8关于LocalDate,Date
关于java8中的新的时间日期类 public static void main(String[] args) { Date date = new Date(); LocalDate localDat ...
- PAT (Basic Level) Practise (中文)- 1015. 德才论 (25)
http://www.patest.cn/contests/pat-b-practise/1015 宋代史学家司马光在<资治通鉴>中有一段著名的“德才论”:“是故才德全尽谓之圣人,才德兼亡 ...
- 为什么要在函数内部声明 var that = this 呢
看一个例子 $('#conten').click(function(){ //this是被点击的#conten var that =this; $('.conten').each(function() ...
- C++ string头文件
转载自https://blog.csdn.net/superna666/article/details/52809007/ 作者 zhenzhenjiajia888 标准c++中string类函数介绍 ...
- PHP使用FTP上传文件到服务器(实战篇)
我们在做开发的过程中,上传文件肯定是避免不了的,平常我们的程序和上传的文件都在一个服务器上,我们也可以使用第三方sdk上传文件,但是文件在第三方服务器上.现在我们使用PHP的ftp功能把文件上传到我们 ...