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. spring maven 包

    <spring-framework.version>.RELEASE</spring-framework.version> <dependency> <gro ...

  2. JS实现2,8,10,16进制的相互转换

    // 10进制转为16进制 var a=1234567890; console.log(a.toString(16)) //499602d2 // 16进制转为10进制 var num=parseIn ...

  3. ES6中const的用法

    const声明一个只读的常量.一旦声明,常量的值就不能改变.且const一旦声明变量,就必须立即初始化,不能留到以后赋值. const的作用域与let命令相同:只在声明所在的块级作用域内有效. con ...

  4. iOS 绘制1像素的线

    一.Point Vs Pixel iOS中当我们使用Quartz,UIKit,CoreAnimation等框架时,所有的坐标系统采用Point来衡量.系统在实际渲染到设置时会帮助我们处理Point到P ...

  5. 如何使Recovery分区正常工作

    通常安装完系统后,在进入Clover菜单选择Recovery分区后是进不去的,对于我这种完美强迫症患者来说这是不能忍的,最后,终于在网上找到个简单办法让它工作,废话不多说,上命令: 先找到Recove ...

  6. vue 正则判断

    value=value.replace(/[^\d.]/g,'').replace(/\.{2,}/g,'.').replace('.','$#$').replace(/\./g,'').replac ...

  7. tensorflow目标检测API之训练自己的数据集

    1.训练文件的配置 将生成的csv和record文件都放在新建的mydata文件夹下,并打开object_detection文件夹下的data文件夹,复制一个后缀为.pbtxt的文件到mtdata文件 ...

  8. LeetCode之Weekly Contest 90

    LeetCode第90场周赛记录 第一题:亲密字符串 问题: 给定两个由小写字母构成的字符串 A 和 B ,只要我们可以通过交换 A 中的两个字母得到与 B 相等的结果,就返回 true :否则返回  ...

  9. thinkcmf5更新模板代码分析,解决模板配置json出错导致数据库保存的配置项内容丢失问题

    private function updateThemeFiles($theme, $suffix = 'html') { $dir = 'themes/' . $theme; $themeDir = ...

  10. 【js】【转发】jreturn;、return true、return false;区别

    一.返回控制与函数结果, 语法为:return 表达式; 语句结束函数执行,返回调用函数,而且把表达式的值作为函数的结果  二.返回控制, 无函数结果,语法为:return;  在大多数情况下,为事件 ...