题面

从零开始的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的更多相关文章

  1. 2021.12.08 P1848 [USACO12OPEN]Bookshelf G(线段树优化DP)

    2021.12.08 P1848 [USACO12OPEN]Bookshelf G(线段树优化DP) https://www.luogu.com.cn/problem/P1848 题意: 当农夫约翰闲 ...

  2. [USACO12OPEN]书架Bookshelf

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

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

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

  4. p1848 [USACO12OPEN]书架Bookshelf

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

  5. POJ 3268 Bookshelf 2 动态规划法题解

    Description Farmer John recently bought another bookshelf for the cow library, but the shelf is gett ...

  6. SCNU ACM 2016新生赛决赛 解题报告

    新生初赛题目.解题思路.参考代码一览 A. 拒绝虐狗 Problem Description CZJ 去排队打饭的时候看到前面有几对情侣秀恩爱,作为单身狗的 CZJ 表示很难受. 现在给出一个字符串代 ...

  7. SCNU ACM 2016新生赛初赛 解题报告

    新生初赛题目.解题思路.参考代码一览 1001. 无聊的日常 Problem Description 两位小朋友小A和小B无聊时玩了个游戏,在限定时间内说出一排数字,那边说出的数大就赢,你的工作是帮他 ...

  8. HDU 3791二叉搜索树解题(解题报告)

    1.题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=3791 2.参考解题 http://blog.csdn.net/u013447865/articl ...

  9. 【BZOJ1700】[Usaco2007 Jan]Problem Solving 解题 动态规划

    [BZOJ1700][Usaco2007 Jan]Problem Solving 解题 Description 过去的日子里,农夫John的牛没有任何题目. 可是现在他们有题目,有很多的题目. 精确地 ...

随机推荐

  1. g2蚂蚁数据可视化折线图,点位坐标label 图形文本设置

    应用g2可视化插件画了个粉丝分析图 要求显示如图所见的节点参数,查看文档蚂蚁图形文本设置,得知需要引入如下代码: chart.point().position('update*praises').la ...

  2. maven实战读书笔记(二)

    一个Spring加载属性的工具类,指定目标位置之后可以用${}的方式加载配置文件 测试maven工程发送email的例子:运行成功的例子—github 常用的命令: mvn clean compile ...

  3. JS特效@缓动框架封装及应用

    | 版权声明:本文为博主原创文章,未经博主允许不得转载. 一.变量CSS样式属性获取/赋值方法 给属性赋值:(既能获取又能赋值) 1)div.style.width 单个赋值:点语法,这个方法比较固定 ...

  4. a标签的href为空的问题

    在表格里写一个a标签链接刷新表格的时候,没注意,把a标签的href设置为""空字符串,导致每次刷新表格之后会再刷新一次整体页面,找了很久都没发现问题出在哪里,最后无意之间,鼠标在一 ...

  5. Servlet 3.0 对异步处理的支持

    Servlet 3.0 实现了对异步处理的支持 通过利用注解@WebServlet(urlPatterns="/AServlet" AysnsSupported=true) 让后n ...

  6. 为什么要读这本书《java编程思想》

    在学校学习编程语言只是浅显的了解,不理解的的东西有很多 ,想通过这本书对java语言有更深的理解,对于以后的学习和工作会有很大的好处.与其了了草草的看你一些书,知其然而不知其所以然,这不是我想要的学习 ...

  7. synchronized、锁、多线程同步的原理是咋样

    先综述个结论: 一般说的synchronized用来做多线程同步功能,其实synchronized只是提供多线程互斥,而对象的wait()和notify()方法才提供线程的同步功能. 一般说synch ...

  8. SQL语句中order_by_、group_by_、having的用法区别

    order by 从英文里理解就是行的排序方式,默认的为升序. order by 后面必须列出排序的字段名,可以是多个字段名. group by 从英文里理解就是分组.必须有“聚合函数”来配合才能使用 ...

  9. PAT 1067 试密码

    https://pintia.cn/problem-sets/994805260223102976/problems/994805266007048192 当你试图登录某个系统却忘了密码时,系统一般只 ...

  10. LR_问题_虚拟用户以进程和线程模式运行的区别

    进程方式和线程方式的优缺点: 如果选择按照进程方式运行, 每个用户都将启动一个mmdrv进程,多个mmdrv进程会占用大量内存及其他系统资源,这就限制了可以在任一负载生成器上运行的并发用户数的数量,因 ...