【NOIP2017】跳房子

本人是NOIP2017的亲历者,两年前这道题我在考场上随便打了个二分暴力,就草草结束了

如今在做这道题,便能简单的AC了

我采用的思路是二分答案,然后用dp判断答案的可行性。定义f[i]表示到i这个格子最大的分数,如果为一个极小值则可以认为这个点无法到达;x[i]表示i的位置,g表示当前二分的答案。

那么存在状态转移方程:

在这里,我们可以维护一个单调队列,存储对于当前i的决策允许集合,使得队列当中的元素x值递增,f值递减,当i改变时,我们维护单调队列即可。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 typedef long long ll;
 7 inline int read() {
 8     int ret=0;
 9     int op=1;
10     char c=getchar();
11     while(c<'0'||c>'9') {if(c=='-') op=-1; c=getchar();}
12     while(c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
13     return ret*op;
14 }
15 int n,dis,num;
16 int x[500010],v[500010],q[500010];
17 ll f[500010];
18 bool check(int g) {
19     int h=1,t=0;
20     memset(q,0,sizeof(q));
21     int now=0;
22     int maxx=dis+g;
23     int minn=max(dis-g,1);
24     for(int i=1;i<=n;i++) {
25         while(x[now]<=x[i]-minn) {
26             if(f[now]<=-1e9) {
27                 now++;
28                 continue ;
29             }
30             while(h<=t&&f[now]>=f[q[t]]) t--;
31             q[++t]=now++;
32         }
33         while(h<=t&&x[q[h]]+maxx<x[i]) h++;
34         if(h<=t) f[i]=f[q[h]]+v[i];
35         else f[i]=-1e9;
36         if(f[i]>=num) return 1;
37     }
38     return 0;
39 }
40 int main() {
41     n=read(); dis=read(); num=read();
42     for(int i=1;i<=n;i++) {
43         x[i]=read();
44         v[i]=read();
45     }
46     int l=0,r=500000000,ans=-1;
47     while(l<=r) {
48         memset(f,0,sizeof(f));
49         int mid=l+r>>1;
50         if(check(mid)) {
51             ans=mid;
52             r=mid-1;
53         }
54         else l=mid+1;
55     }
56     if(ans==-1) puts("-1");
57     else printf("%d
",ans);
58     return 0;
59 }
AC Code
原文地址:https://www.cnblogs.com/shl-blog/p/10990847.html