【NOIP2017】跳房子
来源:互联网 发布:apache 查看编译参数 编辑:程序博客网 时间:2024/05/21 08:43
这题我0分。
比赛时,我一眼出正解,哈哈,太水了!
这题不就是一个二分+DP+单调队列吗?
然而,细节决定成败。
我错了许多细节,就挂了。
我只考了0分。。。
首先,这题满足一个条件:
保证g变大后,如果原来满足条件,现在也会满足条件;而如果原来不满足条件,现在就有可能满足条件。
g变小后,如果原来满足条件,现在不一定会满足条件;而如果原来不满足条件,现在就一定不可能满足条件。
所以,我们可以用二分找出最合适的g的值。
已知,
我们就可以列出状态转移方程了:
其中,a为跳跃最短距离,b为跳跃的最长距离。
这样做的时间复杂度是
所以,我们就要把DP优化一下了。
我们很容易发现,状态转移方程中,对于不同的i,
怎么优化呢?
我们有多种优化方式,其中我推荐两种:大根堆,还有单调队列。大根堆码量大,而单调队列方便快捷,因此我比较喜欢用单调队列。
用
单调队列存的是元素的下标,即
由于这个单调队列是递减的(即第一个元素最大,第二个元素比第一个小,第三个比第二个小……最后一个是最小的),所以我们每次使用的最大值就是单调队列中有效范围内的第一个元素对应的值。
那么我们的状态转移方程就可以变成这个样子了:
其中,a为跳跃最短距离,b为跳跃的最长距离。
这样用起来是很方便的,但是,重点来了——
怎样才能保持单调队列的单调性(使单调队列递减)和有效性(使
首先,我们每一次加入元素时,如果 (new是新加入的元素),也就是说这个样子(越高的值越大):
许多人都会认为要变成下面这个样子:
第i个柱子上面的数字是X[queue[i]]的值。
由于新加入单调队列的数,都是可以跳到第i个格子上的,即
而X又是递增的,所以
但是从5(
因此我们可以把4删掉(即tail-1),最后再把5加入,变成下面这个样子:
有时候我们要删除很多元素,如下面这个例子:
变成
我们就要用一个while循环来删除F值小于等于F[new]的数。
但我们的queue[head]是会过期的(queue[head]跳不到第i个格子),这时我们的queue[head]就不能用了。
我们要删掉queue[head],怎么删掉呢?直接head+1就好了。
最后一点,建议同学们把不能到达的点的F赋值为-maxlongint!
#include<cstdio>using namespace std;#define maxlongint 1999999999int f[500001],queue[500001],x[500001],s[500001];int main(){ freopen("jump.in","r",stdin); freopen("jump.out","w",stdout); int n,d,k,l=0,r=1000000000,mid,i,j,t,ans=-1,maxx,minn,head,tail,last; bool bk,bz; scanf("%d%d%d",&n,&d,&k); for(i=1;i<=n;i++) scanf("%d%d",&x[i],&s[i]); l=0;r=1000000000; while(l<=r) { mid=(l+r)/2; maxx=d+mid;bk=false;bz=true; minn=d-mid;last=0; if(minn<1) minn=1; tail=head=1; queue[1]=0; for(i=1;i<=n;i++) { if(maxx>=x[i]&&minn<=x[i]) { bz=false; break; } } if(bz) { l=mid+1; continue; } for(i=1;i<=n;i++) { f[i]=maxlongint; for(j=last+1;j<i;j++) { if(x[j]+minn>x[i]) break; if(x[j]+maxx<x[i]) continue; last=j; if(f[j]==maxlongint) continue; while(head<=tail&&f[queue[tail]]<=f[j]) queue[tail--]=0; queue[++tail]=j; } while(head<tail&&x[queue[head]]+maxx<x[i]) head++; if(x[queue[head]]+maxx<x[i]||x[queue[head]]+minn>x[i]) f[i]=maxlongint; else f[i]=f[queue[head]]+s[i]; if(f[i]<maxlongint&&f[i]>=k) { bk=true; break; } } if(bk) { ans=mid; r=mid-1; } else l=mid+1; } printf("%d\n",ans); return 0;}
- 【NOIP2017】跳房子
- [NOIP2017普及组]跳房子
- NOIP2017普及组★跳房子
- NOIP2017跳房子(普及T4)
- 【NOIP2017普及组正式赛】跳房子
- 跳房子
- 【NOIP2017普及组T4】跳房子-二分答案+DP单调队列优化
- 河中跳房子
- noip2017
- NOIP2017
- noip2017
- NOIP2017
- NOIP2017
- NOIP2017
- NOIP2017
- NOIP2017
- jQuery跳房子插件hopscotch
- OpenJudge_P8201 河中跳房子
- Java for Web学习笔记(九八):持久化初探(3)JPA小例子(上)
- 换种思路实现RecyclerView嵌套RecyclerView(购物车)复杂效果
- 关于c++中vector的使用
- -精通正则表达式-第三版-第2章笔记
- Hibernate的LockMode
- 【NOIP2017】跳房子
- VS 中常见问题汇总
- 1040. 有几个PAT 当是三个字母组成的可能的时候 用检查到A的时候 A前面P的数量 和A后面 T的数量求组合可能
- [ENVI] 分类后处理
- C#学习笔记——结构体
- macOS: 初探本地资源库中的Security.plist文件的用途
- 利用Gson 是序列化Json可以自定义key值的几种方案
- Unity3d easytouch计算摇杆旋转角度以及摇杆八方向控制角色
- git命令