题目背景

NOIP2017 普及组 T4

题目描述

跳房子,也叫跳飞机,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一。

跳房子的游戏规则如下:

在地面上确定一个起点,然后在起点右侧画 n n n 个格子,这些格子都在同一条直线上。每个格子内有一个数字(整数),表示到达这个 格子能得到的分数。玩家第一次从起点开始向右跳,跳到起点右侧的一个格子内。第二次再从当前位置继续向右跳,依此类推。规则规定:

玩家每次都必须跳到当前位置右侧的一个格子内。玩家可以在任意时刻结束游戏,获得的分数为曾经到达过的格子中的数字之和。

现在小 R 研发了一款弹跳机器人来参加这个游戏。但是这个机器人有一个非常严重的缺陷,它每次向右弹跳的距离只能为固定的 d d d。小 R 希望改进他的机器人,如果他花 g g g 个金币改进他的机器人,那么他的机器人灵活性就能增加 g g g,但是需要注意的是,每 次弹跳的距离至少为 1 1 1。具体而言,当 g < d g<d g<d 时,他的机器人每次可以选择向右弹跳的距离为 d − g , d − g + 1 , d − g + 2 , … , d + g − 1 , d + g d-g,d-g+1,d-g+2,\ldots,d+g-1,d+g d−g,d−g+1,d−g+2,…,d+g−1,d+g;否则当 g ≥ d g \geq d g≥d 时,他的机器人每次可以选择向右弹跳的距离为 1 , 2 , 3 , … , d + g − 1 , d + g 1,2,3,\ldots,d+g-1,d+g 1,2,3,…,d+g−1,d+g。

现在小 R 希望获得至少 k k k 分,请问他至少要花多少金币来改造他的机器人。

输入格式

第一行三个正整数 n , d , k n,d,k n,d,k ,分别表示格子的数目,改进前机器人弹跳的固定距离,以及希望至少获得的分数。相邻两个数 之间用一个空格隔开。

接下来 n n n 行,每行两个整数 x i , s i x_i,s_i xi​,si​ ,分别表示起点到第 i i i 个格子的距离以及第 i i i 个格子的分数。两个数之间用一个空格隔开。保证 x i x_i xi​ 按递增顺序输入。

输出格式

共一行,一个整数,表示至少要花多少金币来改造他的机器人。若无论如何他都无法获得至少 k k k 分,输出 − 1 -1 −1。

样例 #1

样例输入 #1

7 4 10
2 6
5 -3
10 3
11 -3
13 1
17 6
20 2

样例输出 #1

2

样例 #2

样例输入 #2

7 4 20
2 6
5 -3
10 3
11 -3
13 1
17 6
20 2

样例输出 #2

-1

提示

输入输出样例 1 说明

花费 2 2 2 个金币改进后,小 R 的机器人依次选择的向右弹跳的距离分别为 $ 2, 3, 5, 3, 4,3$,先后到达的位置分别为 2 , 5 , 10 , 13 , 17 , 20 2, 5, 10, 13, 17, 20 2,5,10,13,17,20,对应$ 1, 2, 3, 5, 6, 7$ 这 6 6 6 个格子。这些格子中的数字之和 $ 15$ 即为小 R 获得的分数。

输入输出样例 2 说明

由于样例中 7 7 7 个格子组合的最大可能数字之和只有 18 18 18,所以无论如何都无法获得 20 20 20 分。

数据规模与约定

本题共 10 组测试数据,每组数据等分。

对于全部的数据满足 1 ≤ n ≤ 5 × 1 0 5 1 \le n \le 5\times10^5 1≤n≤5×105, 1 ≤ d ≤ 2 × 1 0 3 1 \le d \le2\times10^3 1≤d≤2×103, 1 ≤ x i , k ≤ 1 0 9 1 \le x_i, k \le 10^9 1≤xi​,k≤109, ∣ s i ∣ < 1 0 5 |s_i| < 10^5 ∣si​∣<105。

对于第 1 , 2 1, 2 1,2 组测试数据,保证 n ≤ 10 n\le 10 n≤10。

对于第 3 , 4 , 5 3, 4, 5 3,4,5 组测试数据,保证 n ≤ 500 n \le 500 n≤500。

对于第 6 , 7 , 8 6, 7, 8 6,7,8 组测试数据,保证 d = 1 d = 1 d=1。

浅浅地分析下?

n ≤ 10 n \le 10 n≤10

  • 首先,如果是我去考试,这是第四题啊!这说明这什么,这题是提高组难度的!
  • 于是乎,我会去骗分
  • 我一看,那个 − 1 -1 −1的应该是最好骗的吧,直接把所有正数加起来,如果小于 k k k,那就输出 − 1 -1 −1咯
  • 我的眼睛渐渐地移到了 n ≤ 10 n \le 10 n≤10上,贪婪的目光似要把这 10 10 10分硬生生的拿chi 下diao
  • 我的念头从正数移到了……暴搜上!
  • 枚举所有可能的答案,在判断这个方案是否能达到 k k k,是就输出啦
  • 那个……怎么判断这个方案怎么达到 k k k?
  • 爆枚呗!每个点最多有 n n n个决策,一一枚举再记忆化一下应该可以拿下这10分吧?(我没试过)

n ≤ 500 n \le 500 n≤500

  • 刚刚我们在分析枚举所有可能的答案时,我们是 f o r for for循环一个一个的枚举

  • 有没有更优的枚举方法?

  • 有!因为这一段格子是连续的,我们很容易想到了二分答案

  • 定义两个指针, l l l和 r r r

  • m i d = ( l + r ) / 2 = ( l + r ) > > 1 mid=(l+r)/2=(l+r)>>1 mid=(l+r)/2=(l+r)>>1

  • 如果这个答案可以行( c h e c k ( ) check() check()函数),由于题目要求的是最小,所以答案可能在左边, r = m i d r=mid r=mid,否则答案在右边 l = m i d + 1 l=mid+1 l=mid+1

  • 这里为什么是 r = m i d r=mid r=mid而不是 r = m i d − 1 r=mid-1 r=mid−1? 因为我们输出的是 r r r

  • 现在的重点是怎么写 c h e c k ( ) check() check()函数?

  • 我们刚刚的思路是暴力枚举,再思考一下?

  • 线性的?每个点最多有n个决策?达到 k k k?这怎么看都想动态规划啊

  • 于是我们来设计状态, d p i dp_i dpi​表示跳到了第 i i i个格子所得到的最大分数

d p i = m a x ( d p j + a [ i ] . v a l u e , d p i ) ( m i n n ≤ a [ i ] . p o s − a [ j ] . p o s ≤ m a x x ) dp_i=max(dp_j+a[i].value,dp_i)(minn \le a[i].pos-a[j].pos \le maxx) dpi​=max(dpj​+a[i].value,dpi​)(minn≤a[i].pos−a[j].pos≤maxx)

  • 这里,就有同学有疑问了(应该只有我)有没有可能往前跳?答案是不可能的

  • 想想,如果有三个点从前到后分别是 1 , 2 , 3 1,2,3 1,2,3号,往前跳指的是从 1 1 1跳到 3 3 3,然后跳到 2 2 2,那为何不直接一次跳过去呢?所以只需要往后转移

  • 时间复杂度为 O ( n 2 l o g 2 M A X ( x i ) ) O(n^2log_2MAX(x_i)) O(n2log2​MAX(xi​))

  • 这样就可以过 n ≤ 500 n \le 500 n≤500的点了

    C o d e Code Code

    #include<bits/stdc++.h>using namespace std;
    #define INF 1e9
    struct node{int pos=0,value=0;
    }a[500005];
    int n,d,k;
    int dp[500005];
    bool check(int minn,int maxx){dp[0]=0LL;for(int i=1;i<=n;i++){dp[i]=-INF;for(int j=0;j<i;j++)if(a[i].pos-a[j].pos>=minn&&a[i].pos-a[j].pos<=maxx)dp[i]=max(dp[i],dp[j]+a[i].value);if(dp[i]>=k) return true;}return false;
    }
    int main()
    {cin>>n>>d>>k;for(int i=1;i<=n;i++) cin>>a[i].pos>>a[i].value;int l=0,r=INF;while(l<r){int mid=(l+r)>>1;if(check(max(1,d-mid),d+mid)) r=mid;else l=mid+1;}cout<<(r==INF?-1:r);return 0;}
    

n ≤ 5 ∗ 1 0 5 n \le 5*10^5 n≤5∗105

  • 我们考虑在50分的做法上继续优化
  • 我们看这个复杂度 O ( n 2 l o g 2 M A X ( x i ) ) O(n^2log_2MAX(x_i)) O(n2log2​MAX(xi​)),最大的麻烦是什么?
  • 那肯定是 n 2 n^2 n2啊,有没有办法把 n 2 n^2 n2优化成 n l o g 2 n nlog_2n nlog2​n或 n n n呢?
  • 我们观察 c h e c k ( ) check() check()函数,发现 d p dp dp的转移都是在它之前满足条件的,动态变化的,很自然的想到了单调队列
  • 所以我们只需要维护 d e q u e deque deque就行了
  • 怎么维护呢?
  • 定义一个指针 n o w now now,让他指向第一个可行的点
while(a[i].pos-a[now].pos>maxx&&now<i) now++;
  • 然后扫一遍可行的区间
while(a[i].pos-a[now].pos<=maxx&&a[i].pos-a[now].pos>=minn&&now<i){
  • 更新一下这个点,讲不可行的点从队尾弹出,不可行包括比 d p n o w dp_{now} dpnow​小或者超出了区间
while(!q.empty()&&(dp[q.back()]<=dp[now]||a[i].pos-a[q.back()].pos>maxx)) q.pop_back();
  • 将新的点从队尾 p u s h push push,同时,指针枚举下一个点
q.push_back(now),now++;
  • 最后在 w h i l e while while外,将队首不可行的方案弹出
while(!q.empty()&&a[i].pos-a[q.front()].pos>maxx) q.pop_front();
  • 最后判断和转移
if(!q.empty()) dp[i]=dp[q.front()]+a[i].value;
if(dp[i]>=k) return true;
  • 注意, n o w now now千万不要重新赋值,这样才能保证每个点进出一遍
  • 时间复杂度为 O ( n l o g 2 M A X ( x i ) ) O(nlog_2MAX(x_i)) O(nlog2​MAX(xi​))
  • 记得开 l o n g l o n g long\quad long longlong哦,然后你就可以 A C AC AC啦

C o d e Code Code

#include<bits/stdc++.h>using namespace std;
#define INF 1e18
typedef long long ll;
struct node{ll pos=0,value=0;
}a[500005];
ll n,d,k;
ll dp[500005];
bool check(ll minn,ll maxx){for(int i=1;i<=n;i++) dp[i]=-INF;dp[0]=0LL;deque<int> q;int now=0;for(ll i=1;i<=n;i++){while(a[i].pos-a[now].pos>maxx&&now<i) now++;while(a[i].pos-a[now].pos<=maxx&&a[i].pos-a[now].pos>=minn&&now<i){while(!q.empty()&&(dp[q.back()]<=dp[now]||a[i].pos-a[q.back()].pos>maxx)) q.pop_back(); q.push_back(now);now++;}while(!q.empty()&&a[i].pos-a[q.front()].pos>maxx) q.pop_front();if(!q.empty()) dp[i]=dp[q.front()]+a[i].value;if(dp[i]>=k) return true;}return false;
}
int main()
{cin>>n>>d>>k;for(ll i=1;i<=n;i++) cin>>a[i].pos>>a[i].value;ll l=1,r=a[n].pos;while(l<r){ll mid=(l+r)>>1;if(check(max((long long)1,d-mid),d+mid)) r=mid;else l=mid+1; }cout<<(r==INF?-1:r);return 0;}

[NOIP2017 普及组]跳房子 【题解】相关推荐

  1. P3955 [NOIP2017 普及组] 图书管理员C++题解

    洛谷来源:P3955 [NOIP2017 普及组] 图书管理员 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/sol ...

  2. 信息学奥赛一本通 1414:【17NOIP普及组】成绩 | 洛谷 P3954 [NOIP2017 普及组] 成绩

    [题目链接] ybt 1414:[17NOIP普及组]成绩 洛谷 P3954 [NOIP2017 普及组] 成绩 [题目考点] 1. 算术表达式 2. 自动类型转换 低精度类型与高精度类型计算结果是高 ...

  3. 信息学奥赛一本通 1415:【17NOIP普及组】图书管理员 | 洛谷 P3955 [NOIP2017 普及组] 图书管理员

    [题目链接] ybt 1415:[17NOIP普及组]图书管理员 洛谷 P3955 [NOIP2017 普及组] 图书管理员 [题目考点] 1. 枚举 2. 二分 [解题思路] 解法1:枚举 对于每个 ...

  4. noi2017初赛c语言试题,NOIP2017普及组初赛试题及答案

    原标题:NOIP2017普及组初赛试题及答案 清北学堂信息学金牌教研团今天为学生们整理了NOIP2017普及组初赛试题及答案,供学生们参考哦! --此文2100多文字,大概需要60分钟看完 一.单项选 ...

  5. P3954 [NOIP2017 普及组] 成绩(python3实现)

    https://www.luogu.com.cn/problem/P3954 """P3954 [NOIP2017 普及组] 成绩 https://www.luogu.c ...

  6. P1008 [NOIP1998 普及组] 三连击 题解

    P1008 [NOIP1998 普及组] 三连击 题解 题目背景 本题为提交答案题,您可以写程序或手算在本机上算出答案后,直接提交答案文本,也可提交答案生成程序. 题目描述 将 1, 2, - , 9 ...

  7. [NOIP2017 普及组] 棋盘

    [NOIP2017 普及组] 棋盘 题目背景 NOIP2017 普及组 T3 题目描述 有一个m×mm \times mm×m的棋盘,棋盘上每一个格子可能是红色.黄色或没有任何颜色的.你现在要从棋盘的 ...

  8. P3954 [NOIP2017 普及组] 成绩

    题目背景 NOIP2017 普及组 T1 题目描述 牛牛最近学习了 C++ 入门课程,这门课程的总成绩计算方法是: 总成绩=作业成绩×20%+\times 20\%+×20%+小测成绩×30%+×30 ...

  9. ybt1414 成绩(NOIP2017普及组第1题)

    ybt1414  成绩(NOIP2017普及组第1题) 时空限制    1000ms/64MB 题目描述 牛牛最近学习了C++入门课程,这门课程的总成绩计算方法是: 总成绩=作业成绩×20%+小测成绩 ...

最新文章

  1. Centos7源码安装mysql及读写分离,互为主从
  2. wpf单容器中的Chrome
  3. 线性回归竟然还有不明白的地方
  4. 如何知道自己的研究课题是不是领域热点?
  5. php伪静态失败,php伪静态后html不能访问怎么办
  6. java调用短信接口使用实例
  7. tensorflow-gpu_TensorFlow GPU单机多卡训练amp;reloadamp;predict
  8. 基于python的表情识别_python表情识别
  9. zlx生病.高热惊厥_zc20180306
  10. mysql 预处理stmt操作(写入数据库和从数据库中取出)
  11. 触发器(SR锁存器、SR触发器、JK触发器、D触发器、T触发器)
  12. oracle 查询表空间所有表、及表所有的表空间
  13. 搭建MYSQL的mmm架构出现 master/AWAITING_RECOVERY. Roles报错
  14. http响应最大时长 nginx_请问一下该如何用nginx 设置响应时间?
  15. CodeForces - 743B
  16. 临沂大学计算机网络期末考试题,临沂大学2019版计算机网络实验指导书.pdf
  17. 关于4A(统一安全管理平台)系统的理解
  18. ARM的强硬未能吓住高通,高通和中国芯片的远离导致ARM前景黯淡
  19. 手机网游是移动应用的第一个热潮——武春雷专访
  20. UTC时间与当地时间

热门文章

  1. 路由器、交换机、集线器三剑客有什么区别?分别是用来干什么的?
  2. 历年英语计算机统考真题,2018年计算机应用基础统考题库网考原题真题(完整版)...
  3. matlab怎样编程形成软件_matlab是什么编程语言?matlab是编程语言吗
  4. 【第一章 | 操作系统概述】《操作系统 慕课版》课后答案 + 复习
  5. VS项目中配置matplotlib-cpp绘制图片
  6. 百度竞价关键词质量度提升的方法你知道多少?
  7. 其他问题怎么创建百度指数
  8. js 获取当前时间的24小时倒计时
  9. 美颜SDK如何进行Android和iOS双端开发?
  10. 【监控施工项目必备】