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. 用Jersey为Android客户端开发Restful Web Service

    平时在做Android客户端的时候经常要与服务器之间通信,客户端通过服务端提供的接口获取数据,然后再展示在客户端的界面上,作为Android开发者,我们平时更多的是关注客户端的开发,而对服务端开发的关 ...

  2. 解决nginx bind() to 0.0.0.0:80 failed 问题

    nginx的配置文件一开始默认是80端口,出现这个错误多半是80端口已经被占用.这时候只需要把 server { listen 8088; server_name localhost lcsf.com ...

  3. [神经网络]一步一步使用Mobile-Net完成视觉识别(五)

    1.环境配置 2.数据集获取 3.训练集获取 4.训练 5.调用测试训练结果 6.代码讲解 本文是第五篇,讲解如何调用测试训练结果. 上一篇中我们输出了训练的模型,这一篇中我们通过调用训练好的模型来完 ...

  4. HTML_3

    html列表 有序列表:在网页上定义一个有编号的内容列表可以用<ol>.<li>配合使用来实现,在网页上生成的列表,每条项目上按1.2.3编号,有序列表在实际开发中较少使用.代 ...

  5. C-基础:形参char *&p与char *p

    char* &p:以引用传递的方式传指针char* p: 以值传递的方式传指针

  6. 用户输入和while循环

    函数input()的工作原理 message=input('Tell me something,and I will repeat it back to you:') print(message) 编 ...

  7. java8关于LocalDate,Date

    关于java8中的新的时间日期类 public static void main(String[] args) { Date date = new Date(); LocalDate localDat ...

  8. Bootstrap历练实例:导航内的下拉菜单

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  9. 吐槽在cocos2dx游戏接入腾讯信鸽的坑

    腾讯信鸽是用来在后台推送消息给移动应用客户端使用,接入方法很简单,在信鸽官网注册个账号 http://xg.qq.com/xg,然后注册一个应用,在后台页面获得ACCESS ID, ACCESS KE ...

  10. Linux下如何通过命令检查网卡是否插上网线

    How To:Linux下如何通过命令检查网卡是否插上网线   主要工具为ethtool来检查,主要关注的字段为"Link detected",注意如下的输出,其中em4实际物理上 ...