Description

当农夫约翰闲的没事干的时候,他喜欢坐下来看书。多年过去,他已经收集了 N 本书 (1 <= N <= 100,000), 他想造一个新的书架来装所有书。

每本书 i 都有宽度 W(i) 和高度 H(i)。书需要按顺序添加到一组书架上;比如说,第一层架子应该包含书籍1 ... k,第二层架子应该以第k + 1本书开始,以下如此。每层架子的总宽度最大为L(1≤L≤1,000,000,000)。每层的高度等于该层上最高的书的高度,并且整个书架的高度是所有层的高度的总和,因为它们都垂直堆叠。

请帮助农夫约翰计算整个书架的最小可能高度。

有N(1 <= N <= 100000)本书,每本书有一个宽度W(i),高度H(i),(1 <= H(i) <= 1,000,000; 1 <= W(i) <= L)。

现在有足够多的书架,书架宽度最多是L (1 <= L <= 1,000,000,000),把书按顺序(先放1,再放2.....)放入书架。某个书架的高度是该书架中所放的最高的书的高度。

将所有书放入书架后,求所有书架的高度和的最小值?

solution

弄了好久啊,首先这个DP没法维护啊,最后弄出一个暴力均摊的线段树做法.

\(f[i]=f[j]+v[j+1][i]\),这是原DP方程,\(v[j][i]\)表示\(j-i\)间的最大值.

考虑优化:

我们在线段树中,分别维护 \(f[j]\) 和 \(v[j]\),单调指针扫描,扫到 \(i\) 时,用 \(H[i]\) 取更新 \([1,i-1]\) 的 \(v\) 值.

再维护一个\(f[j]+v[j]\),那么转移就是线段树查最值了.

关键在于修改的复杂度:

维护一个区间最小值和区间最大值:

1.如果最小值大于 \(H[i]\),那么没有修改的必要,直接返回

2.如果最大值小于 \(H[i]\),那么直接打上覆盖标记即可

复杂度的证明:

一个无单调性的序列经过一次暴力修改之后,就会变成单调递增或递减序列了,那么下一次修改就会只会选择其中一部分进行修改(因为另一部分总会碰到上述两个剪枝中的一种情况),并且修改完之后依旧是满足单调性的,所以除了第一次修改之外,之后就是线段树修改的复杂度了,均摊 \(O(n*logn)\),常数有些大

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define ls (o<<1)
#define rs (o<<1|1)
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=100005;const ll inf=1e15;
int n,m,v[N],lazy[N<<2],mx[N<<2],mn[N<<2];ll f[N<<2],a[N],g[N<<2];
inline void upd(RG int o){
f[o]=Min(f[ls],f[rs]);
mx[o]=Max(mx[ls],mx[rs]);
mn[o]=Min(mn[ls],mn[rs]);
}
inline void pushdown(RG int o){
if(!lazy[o])return ;
int k=lazy[o];
f[ls]=g[ls]+k;mx[ls]=k;mn[ls]=k;
f[rs]=g[rs]+k;mx[rs]=k;mn[rs]=k;
lazy[ls]=k;lazy[rs]=k;
lazy[o]=0;
}
inline void Modify(int l,int r,int o,int sa,int se,int t){
if(l!=r)pushdown(o);
if(mn[o]>=t)return ;
if(sa<=l && r<=se){
if(mx[o]<t){
lazy[o]=t;f[o]=g[o]+t;mx[o]=mn[o]=t;
return ;
}
}
if(l==r)return ;
int mid=(l+r)>>1;
if(se<=mid)Modify(l,mid,ls,sa,se,t);
else if(sa>mid)Modify(mid+1,r,rs,sa,se,t);
else Modify(l,mid,ls,sa,mid,t),Modify(mid+1,r,rs,mid+1,se,t);
upd(o);
}
inline void updata(int l,int r,int o,int sa,ll t){
if(l==r){g[o]=t;return ;}
int mid=(l+r)>>1;
pushdown(o);
if(sa<=mid)updata(l,mid,ls,sa,t);
else updata(mid+1,r,rs,sa,t);
g[o]=Min(g[ls],g[rs]);
}
inline ll qry(int l,int r,int o,int sa,int se){
if(l!=r)pushdown(o);
if(sa<=l && r<=se)return f[o];
int mid=(l+r)>>1;ll ret,q1,q2;
if(se<=mid)ret=qry(l,mid,ls,sa,se);
else if(sa>mid)ret=qry(mid+1,r,rs,sa,se);
else{
q1=qry(l,mid,ls,sa,mid),q2=qry(mid+1,r,rs,mid+1,se);
ret=Min(q1,q2);
}
upd(o);
return ret;
}
int l=0;
void work()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d%lld",&v[i],&a[i]),a[i]+=a[i-1];
ll tmp;
for(int i=1;i<=n;i++){
while(l<i && a[i]-a[l]>m)l++;
Modify(0,n,1,0,i-1,v[i]);
tmp=qry(0,n,1,l,i-1);
if(i!=n)updata(0,n,1,i,tmp);
}
cout<<tmp<<endl;
} int main()
{
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
work();
return 0;
}

[USACO12OPEN]书架Bookshelf的更多相关文章

  1. [Luogu1848][USACO12OPEN]书架Bookshelf DP+set+决策单调性

    题目链接:https://www.luogu.org/problem/show?pid=1848 题目要求书必须按顺序放,其实就是要求是连续的一段.于是就有DP方程$$f[i]=min\{f[j]+m ...

  2. p1848 [USACO12OPEN]书架Bookshelf

    分析 单调队列优化dp即可 正确性显然,详见代码 代码 #include<bits/stdc++.h> using namespace std; #define int long long ...

  3. 书架 bookshelf

    书架 bookshelf 题目描述 当Farmer John闲下来的时候,他喜欢坐下来读一本好书. 多年来,他已经收集了N本书 (1 <= N <= 100,000). 他想要建立一个多层 ...

  4. pkuwc 前的任务计划

    菜鸡 wxw 的计划(肯定会咕咕咕 12.27 luogu P4244 [SHOI2008]仙人掌图 II(咕咕咕 luogu P4246 [SHOI2008]堵塞的交通 (没有咕! luogu P1 ...

  5. Java设计模式学习记录-迭代器模式

    前言 这次要介绍的是迭代器模式,也是一种行为模式.我现在觉得写博客有点应付了,前阵子一天一篇,感觉这样其实有点没理解透彻就写下来了,而且写完后自己也没有多看几遍,上次在面试的时候被问到java中的I/ ...

  6. English trip -- VC(情景课)10 B Around the house 在家里

    Vocablulary focus  核心词汇 cook play the guitar listen to music watch TV read magazines work in the gar ...

  7. Python之Django的Model详解

    一.创建数据库 创建数据库 进入数据库: mysql -uroot -p 创建数据库: CREATE DATABASE test1 CHARSET=utf8; 连接数据库 虚拟环境中安装数据库模块:p ...

  8. 设计模式——迭代器(Iterator)模式

    概述 迭代器模式简单的说(按我目前的理解)就是一个类提供一个对外迭代的接口,方面调用者迭代.这个迭代接口至少包括两个方法:hasNext()--用于判断是否还有下一个,next()--用于取出下一个对 ...

  9. XStream的基本使用

    先准备两个bean public class Book { private int bookId; private String bookName; private String bookCode; ...

随机推荐

  1. 201621123057 《Java程序设计》第6周学习总结

    1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图或相关笔记,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰 ...

  2. C语言——第一次作业

    **学习内容总结** 本周进行了算法的初步学习,用计算机的思维方式去思考问题,并学习了如何用传统程序框图表示算法. 相关内容: 1.算法是用来解决问题的方法与步骤. 2.计算机擅长重复,常用枚举的方法 ...

  3. 《高级软件测试》Windows平台Jira的配置

    昨天完成了Jira的下载,很开心地去睡觉等明天天亮秒配环境愉快进行使用,撰写文档,开始徜徉于软件管理测试实践,早日走向代码巅峰. 我们把安装和配置的过程来走一遍. 安装完成汤姆猫长这样子: 安装Jir ...

  4. 动手写IL到Lua的翻译器——准备

    文章里的代码粘过来的时候格式有点问题,原因是一开始文章是在订阅号上写的(gamedev101,文末有二维码),不知道为啥贴过来就没了格式,还要手动删行号,就没搞了. 介绍下问题背景: 小说君正在参与的 ...

  5. python 常用算法学习(2)

    一,算法定义 算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制.也就是说,能够对一定规范的输入,在有限时间内获得所要求 ...

  6. python 人工智能资源推荐

    原创 2017-06-05 玄魂工作室 玄魂工作室 我翻了翻我自己曾经看过的书,还是放弃了推荐.原因很简单,我对这个领域并不是很熟悉,我来推荐资源有点误人子弟.so,简单推点其他人建议给我的内容,希望 ...

  7. python random 模块的用法

    Python中的random模块用于生成随机数.下面介绍一下random模块中最常用的几个函数. random.random random.random()用于生成一个0到1的随机符点数: 0 < ...

  8. PHP常用函数集合

    PHP常用函数总结 数学函数 1.abs(): 求绝对值 $abs = abs(-4.2); //4.2 数字绝对值数字 2.ceil(): 进一法取整 echo ceil(9.999); // 10 ...

  9. windows server 2016远程桌面进去,英文系统修改语言

    由于我这边已经是改好了,以下截图来自中文版. 这边选了中文,然后点options. 选择:使该语言成为主要语言,保存. 会提示需要退出登录. 过一会重新登录,ok.

  10. JavaScript 以及 css3进度条

    JavaScript css3进度条 使用css3实现进度条 <!DOCTYPE html> <html lang="en"> <head> & ...