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的更多相关文章

  1. [USACO2012 OPEN] Bookshelf

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=2678 [算法] 首先不难想到如下DP : 记f[i]表示前i本书的高度和最小值 显然 ...

  2. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  3. bookshelf

    nodejs mysql ORM 比node-mysql好用多了. bookshelf 支持restful功能,用到的时候研究下:https://www.sitepoint.com/getting-s ...

  4. POJ3628 Bookshelf 2(01背包+dfs)

    Bookshelf 2 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8745   Accepted: 3974 Descr ...

  5. Bookshelf 2

    Bookshelf 2 Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit  ...

  6. POJ 3628 Bookshelf 2(01背包)

    Bookshelf 2 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9488   Accepted: 4311 Descr ...

  7. 动态规划(状态压缩):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 ...

  8. BZOJ3016: [Usaco2012 Nov]Clumsy Cows

    3016: [Usaco2012 Nov]Clumsy Cows Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 71  Solved: 52[Submi ...

  9. BZOJ 3011: [Usaco2012 Dec]Running Away From the Barn( dfs序 + 主席树 )

    子树操作, dfs序即可.然后计算<=L就直接在可持久化线段树上查询 -------------------------------------------------------------- ...

随机推荐

  1. 分享一些关于Lucene的心得

    Lucene的概述 Lucene是一个全文搜索框架,而不是应用产品.因此它并不像http://www.baidu.com/ 或者google Desktop那么拿来就能用,它只是提供了一种工具让你能实 ...

  2. vue 修改端口

  3. HTML 标签(一)

    HTML HTML:超文本编辑语言(标签语言) 浏览器顺序渲染,从上到下,从左到右 是树型的 html格式 标签的属性是关键 meta标签 可提供有关页面的元信息 <meta charset=& ...

  4. Python re module (regular expressions)

    regular expressions (RE) 简介 re模块是python中处理正在表达式的一个模块 r"""Support for regular expressi ...

  5. 解决cocos simpleAudioEngine播放mp3失败问题

    今天用cocos3.x版本实现游戏音乐播放发现一个坑,策划发来的mp3格式音频,用 simpleAudioEngine无法播放, 以为是路径问题,断点调试没找到,然后拷贝了cocos自带的mp3音频文 ...

  6. 初涉网络流[EK&dinic]

    主要还是板子 Edmonds-Karp 从S开始bfs,直到找到一条到达T的路径后将该路径增广,并重复这一过程. 在处理过程中,为了应对“找到的一条路径把其他路径堵塞”的情况,采用了建反向弧的方式来实 ...

  7. 【wqs二分】HHHOJ#15. 赤

    这个wqs二分并不熟练…… 题目描述 #15. 赤 题目分析 两维都用wqs二分,其他没有什么特殊之处. 重点在于,wqs二分还原最优解的时候,增量是强制给的k. #include<bits/s ...

  8. 【Git版本控制】git将单个文件回退到某一版本

    暂定此文件为a.jsp 1.进入到a.jsp所在目录,通过 git  log a.jsp查看a.jsp的更改记录 2.找到想要回退的版本号:例如 fcd2093 通过 git reset   fcd2 ...

  9. Win10家庭版找不到组策略gpedit.msc

    首先在桌面上建立一个txt文本文件,将下面的代码复制到里面 @echo off pushd "%~dp0" dir /b C:\Windows\servicing\Packages ...

  10. 用宝塔软件在linux上自动安装php环境

    1.确保是纯净系统 确保是干净的操作系统,没有安装过其它环境带的Apache/Nginx/php/MySQL,否则安装不上 2.sudo进行安装 yum install -y wget &&a ...