解题:USACO12OPEN Bookshelf
从零开始的DP学习之肆
当DP方程中的一部分具有某种单调性时可以用数据结构或者预处理维护来降低复杂度
一开始没有看懂题,尴尬,后来发现题目可以简化成这个样子: 将一个序列划分为若干段,每段长度不超过$L$,求每段中最大值之和的最小值
看起来可以直接二分,然而大概并不可行,不过我们有一个明显的$O(n^2)$的DP思路,和我最近做的一道题思路一样。设$dp[i]$表示以$i$为结尾的最小花费,枚举结尾$i$,在$1->i$中找到所有与$i$间距不超过$L$的$j$来转移,代价就是$(j,i)$中的最大值,可以ST表预处理。即$dp[i]=min(dp[i],dp[j]+max(j,i))(j<=i\&\&\sum\limits_{k=j}^i width[k]<=L)$
考虑如何优化,发现$dp$数组在顺序下是单调不下降的,而当右端点$i$确定时,所有的$j$的最大值在顺序下是单调不上升的,所以我们可以考虑用线段树维护这个最小花费,也就是维护$dp[j]+max(j,i)$的最小值。我们枚举右端点时候相当于移动一个长度不超过$L$的滑动窗口,然后我们对于每个新加入的高度就维护一下它左边这段的最大高度,求出$dp[i]$后再单点修改一下下一个位置就可以了
具体来说是用线段树维护四个值+一个标记:最小值,最大值,dp数组,最小花费。其中最小值是为了在维护最大值的时候二分用的,当找到一个要修改的区间的时候我们二分出要修改的那一块,具体来说就是这块中的最小值小于我们要修改成的值再进去修改。然后说说这只蒟蒻都WA了什么鬼畜的错误,第一次是pushup用串了(雾);第二次是因为调试的时候写的和平时不太一样了,然后线段树release了叶子节点=。=;最后一次发现是区间没卡准(之前都是怎么过的2333)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=;
long long dp[*N],mini[*N],maxx[*N];
long long laz[*N],val[*N];
long long w[N],h[N];
long long n,m,f,tot,ans;
void pushup(int nde)
{
int ls=*nde,rs=*nde+;
maxx[nde]=max(maxx[ls],maxx[rs]);
mini[nde]=min(mini[ls],mini[rs]);
val[nde]=min(val[ls],val[rs]);
}
void release(int nde)
{
if(laz[nde])
{
int ls=*nde,rs=*nde+;
laz[ls]=mini[ls]=maxx[ls]=laz[nde];
laz[rs]=mini[rs]=maxx[rs]=laz[nde];
val[ls]=dp[ls]+maxx[ls],val[rs]=dp[rs]+maxx[rs]; laz[nde]=;
}
}
void change1(int nde,int l,int r,int nl,int nr,long long task)
{
if(l>nr||r<nl) return ;
if(l!=r) release(nde); int mid=(l+r)/,ls=*nde,rs=*nde+;
if(l>=nl&&r<=nr)
{
if(task<=maxx[nde])
{
if(task>mini[ls]) change1(ls,l,mid,nl,nr,task);
if(task>mini[rs]) change1(rs,mid+,r,nl,nr,task);
}
else
{
maxx[nde]=mini[nde]=laz[nde]=task;
val[nde]=dp[nde]+maxx[nde]; return ;
}
}
else
change1(ls,l,mid,nl,nr,task),change1(rs,mid+,r,nl,nr,task);
pushup(nde);
}
void change2(int nde,int l,int r,int pos,long long task)
{
if(l==pos&&r==pos) {dp[nde]=task; return ;}
release(nde); int mid=(l+r)/,ls=*nde,rs=*nde+;
if(pos<=mid) change2(ls,l,mid,pos,task);
else change2(rs,mid+,r,pos,task);
dp[nde]=min(dp[ls],dp[rs]);
}
long long query(int nde,int l,int r,int nl,int nr)
{
if(l>nr||r<nl)
return 1e18;
else if(l>=nl&&r<=nr)
return val[nde];
else
{
int mid=(l+r)/,ls=*nde,rs=*nde+; release(nde);
return min(query(ls,l,mid,nl,nr),query(rs,mid+,r,nl,nr));
}
}
int main ()
{
scanf("%lld%lld",&n,&m),f=;
for(int i=;i<=n;i++)
scanf("%lld%lld",&h[i],&w[i]);
for(int i=;i<=n;i++)
{
tot+=w[i];
while(tot>m) tot-=w[f++];
change1(,,n,,i,h[i]);
ans=query(,,n,f,i);
if(i!=n) change2(,,n,i+,ans);
}
printf("%lld",ans);
return ;
}
解题:USACO12OPEN Bookshelf的更多相关文章
- 2021.12.08 P1848 [USACO12OPEN]Bookshelf G(线段树优化DP)
2021.12.08 P1848 [USACO12OPEN]Bookshelf G(线段树优化DP) https://www.luogu.com.cn/problem/P1848 题意: 当农夫约翰闲 ...
- [USACO12OPEN]书架Bookshelf
Description 当农夫约翰闲的没事干的时候,他喜欢坐下来看书.多年过去,他已经收集了 N 本书 (1 <= N <= 100,000), 他想造一个新的书架来装所有书. 每本书 i ...
- [Luogu1848][USACO12OPEN]书架Bookshelf DP+set+决策单调性
题目链接:https://www.luogu.org/problem/show?pid=1848 题目要求书必须按顺序放,其实就是要求是连续的一段.于是就有DP方程$$f[i]=min\{f[j]+m ...
- p1848 [USACO12OPEN]书架Bookshelf
分析 单调队列优化dp即可 正确性显然,详见代码 代码 #include<bits/stdc++.h> using namespace std; #define int long long ...
- POJ 3268 Bookshelf 2 动态规划法题解
Description Farmer John recently bought another bookshelf for the cow library, but the shelf is gett ...
- SCNU ACM 2016新生赛决赛 解题报告
新生初赛题目.解题思路.参考代码一览 A. 拒绝虐狗 Problem Description CZJ 去排队打饭的时候看到前面有几对情侣秀恩爱,作为单身狗的 CZJ 表示很难受. 现在给出一个字符串代 ...
- SCNU ACM 2016新生赛初赛 解题报告
新生初赛题目.解题思路.参考代码一览 1001. 无聊的日常 Problem Description 两位小朋友小A和小B无聊时玩了个游戏,在限定时间内说出一排数字,那边说出的数大就赢,你的工作是帮他 ...
- HDU 3791二叉搜索树解题(解题报告)
1.题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=3791 2.参考解题 http://blog.csdn.net/u013447865/articl ...
- 【BZOJ1700】[Usaco2007 Jan]Problem Solving 解题 动态规划
[BZOJ1700][Usaco2007 Jan]Problem Solving 解题 Description 过去的日子里,农夫John的牛没有任何题目. 可是现在他们有题目,有很多的题目. 精确地 ...
随机推荐
- 从零开始的Python学习Episode 19——面向对象(2)
面向对象之继承 继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类又可称 为基类或超类,新建的类称为派生类或子类. 子类会“”遗传”父类的属性,从而解决代码重用问 ...
- Vue 入门之概念
Vue 简介 Vue 是一个前端的双向绑定类的框架,发音[读音 /vjuː/, 类似于 [view].新的 Vue 版本参考了 React 的部分设计,当然也有自己独特的地方,比如 Vue 的单文件组 ...
- LeetCode 404. Sum of Left Leaves (C++)
题目: Find the sum of all left leaves in a given binary tree. Example: 3 / \ 9 20 / \ 15 7 There are t ...
- LeetCode 455. Assign Cookies (C++)
题目: Assume you are an awesome parent and want to give your children some cookies. But, you should gi ...
- java实验1实验报告(20135232王玥)
实验一 Java开发环境的熟悉 一.实验内容 1. 使用JDK编译.运行简单的Java程序 2.使用Eclipse 编辑.编译.运行.调试Java程序 二.实验要求 1.没有Linux基础的同学建议先 ...
- Leetcode题库——13.罗马数字转整数
@author: ZZQ @software: PyCharm @file: Luoma2Int.py @time: 2018/9/16 17:06 要求: 罗马数字转数字 字符 数值 I 1 V 5 ...
- Codeforces Round #106 (Div. 2) D. Coloring Brackets 区间dp
题目链接: http://codeforces.com/problemset/problem/149/D D. Coloring Brackets time limit per test2 secon ...
- java equals()方法的注意事项
1.在写代码的时候,我们有时候需要判断两个相同类的对象的值是否全部相等,很多人想到的就是equals()方法,但是equals方法真的是可以比较吗?其实equals方法比较的并不是两个对象的值,它只是 ...
- Hibernate 延迟加载 分析
出处:http://www.ibm.com/developerworks/cn/java/j-lo-hibernatelazy/#icomments Hibernate 的延迟加载(lazy load ...
- Team饭来了团队作业3需求改进与系统设计
团队名称:饭来了 人员组成: 队长:侯晓东 学号:2016012087 队员:崔啸寒 学号:2016012006 队员:方柱权 学号:201601 ...