解题: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的牛没有任何题目. 可是现在他们有题目,有很多的题目. 精确地 ...
随机推荐
- Mysql读写分离——主从数据库+Atlas
mysql集群 最近在参加项目开发微信小程序后台,由于用户数量巨大,且后台程序并不是很完美,所以对用户的体验很是不友好(简单说就是很卡).赶巧最近正在翻阅<大型网站系统与Java中间件实践> ...
- 新手Python第四天(生成器)
Python 生成器 生成器和生成表达式 a=[i*2 for i in range(10)]#生成表达式 b=(i*2 for i in range(10))#生成器 生成器的特点:优点(不占用内存 ...
- eos源码编译
编译源码 运行代码 在阿里云 纽约服务器上运行没有出现任何问题. 在其他电脑上出现很多问题. 搜集到的问题如下: 随着EOSIO软件越来越成熟,后来的开发者也越来越幸福.EOS相关源码的编译和运行变得 ...
- 编译Android VNC Server
1,在如下地址checkout源代码,我checkout的版本为0.9.7http://code.google.com/p/android-vnc-server/source/checkout 2,在 ...
- can总线实现stm32的IAP
使用stm32f105rct6的can通信做IAP,实现固件的远程更新功能.IAP的实现包括两个程序:BootLoader和应用程序.启动过程先启动BootLoader,等待1s,若接收到烧写指令则开 ...
- paste命令详解
基础命令学习目录首页 原文链接:https://blog.csdn.net/u011341352/article/details/52806312 个人分类: linux paste命令和cut命 ...
- HDU 1556 Color the ball (一维树状数组,区间更新,单点查询)
中文题,题意就不说了 一开始接触树状数组时,只知道“单点更新,区间求和”的功能,没想到还有“区间更新,单点查询”的作用. 树状数组有两种用途(以一维树状数组举例): 1.单点更新,区间查询(即求和) ...
- 《Java学习笔记JDK8》学习总结
chapter 6 继承与多态 6.1何谓继承 1.继承的定义:继承就是避免多个类间重复定义共同行为. 2.总结:教材中通过设计一款RPG游戏的部分代码向我们展示了“重复”程序代码的弊端,为了改进 ...
- MAX值-单元测试
#include<iostream> using namespace std; int Largest(int list[], int length); // list[]:求最大值的函数 ...
- Scapy之ARP询问
引言 校园网中,有同学遭受永恒之蓝攻击,但是被杀毒软件查下,并知道了攻击者的ip也是校园网.所以我想看一下,这个ip是PC,还是路由器. 在ip视角,路由器和pc没什么差别. 实现 首先是构造arp报 ...