NOIP2017普及组★跳房子
来源:互联网 发布:淘宝店铺搜索排名 编辑:程序博客网 时间:2024/05/18 02:34
- 题目
- 问题描述
- 输入格式
- 输出格式
- 输入输出样例1
- 输入输出样例1 说明
- 输入输出样例2
- 输入输出样例2 说明
- 输入输出样例3
- 数据规模与约定
- 分析
- 二分答案
- DP
- 单调队列优化
- 代码
题目
跳房子
- (jump.cpp/c/pas)
- 2S
- 10 * 10’
- 传统
- 256MB
【问题描述】
跳房子,也叫跳飞机,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一。
跳房子的游戏规则如下:
在地面上确定一个起点,然后在起点右侧画n 个格子,这些格子都在同一条直线上。每
个格子内有一个数字(整数),表示到达这个格子能得到的分数。玩家第一次从起点开始向
右跳,跳到起点右侧的一个格子内。第二次再从当前位置继续向右跳,依此类推。规则规定:
玩家每次都必须跳到当前位置右侧的一个格子内。玩家可以在任意时刻结束游戏,获得的分
数为曾经到达过的格子中的数字之和。
现在小R 研发了一款弹跳机器人来参加这个游戏。但是这个机器人有一个非常严重的
缺陷,它每次向右弹跳的距离只能为固定的d。小R 希望改进他的机器人,如果他花g 个金
币改进他的机器人,那么他的机器人灵活性就能增加g,但是需要注意的是,每次弹跳的距
离至少为1。具体而言:
当g < d时,他的机器人每次可以选择向右弹跳的距离为d-g, d-g+1,d-g+2,…,d+g-2,d+g-1,d+g;
否则(当g ≥ d时),他的机器人每次可以选择向右弹跳的距离为1,2,3,…,d+g-2,d+g-1,d+g。
现在小R 希望获得至少k 分,请问他至少要花多少金币来改造他的机器人。
【输入格式】
输入文件名为jump.in。
第一行三个正整数n,d,k,分别表示格子的数目,改进前机器人弹跳的固定距离,以
及希望至少获得的分数。相邻两个数之间用一个空格隔开。
接下来n 行,每行两个正整数xi ,si,分别表示起点到第i个格子的距离以及第i个格子的
分数。两个数之间用一个空格隔开。保证xi按递增顺序输入。
【输出格式】
输出文件名为jump.out。
共一行,一个整数,表示至少要花多少金币来改造他的机器人。若无论如何他都无法获
得至少k 分,输出-1。
【输入输出样例1】
jump.in 7 4 10
2 6
5 -3
10 3
11 -3
13 1
17 6
20 2
jump.out 2
见选手目录下的jump/jump1.in 和jump/jump1.ans。
【输入输出样例1 说明】
花费 2 个金币改进后,小R 的机器人依次选择的向右弹跳的距离分别为2,3,5,3,4,
3,先后到达的位置分别为2,5,10,13,17,20,对应1, 2, 3, 5, 6, 7 这6 个格子。这些格
子中的数字之和15 即为小R 获得的分数。
【输入输出样例2】
jump.in 7 4 20
2 6
5 -3
10 3
11 -3
13 1
17 6
20 2
jump.out -1
见选手目录下的jump/jump2.in 和jump/jump2.ans。
【输入输出样例2 说明】
由于样例中7 个格子组合的最大可能数字之和只有18 ,无论如何都无法获得20 分。
【输入输出样例3】
见选手目录下的jump/jump3.in 和jump/jump3.ans。
【数据规模与约定】
本题共10 组测试数据,每组数据10 分。对于全部的数据满足1 ≤ n ≤ 500000, 1 ≤ d ≤
2000, 1 ≤ xi , k ≤ 109, |si| < 105。
对于第1,2 组测试数据,n ≤ 10;
对于第3,4,5 组测试数据,n ≤ 500
对于第6,7,8 组测试数据,d = 1
分析
二分答案
显然答案有单调性,所以二分答案。
有这么简单?显然作为第4题,它不会这么简单:怎么判断答案大了还是小了?
DP
肯定不能贪心,发现它完全可以DP,还是线性的。
于是:
这样就可以判断答案的合法性了,有这么简单,它不会这么简单,算一下时间复杂度:
单调队列优化
所以,要优化DP……
发现转移式中的
单调队列是一个双向队列(deque),即两头都可以push或者pop等。
怎么优化呢?假设此时队列里面已经有了
发现,对于格子
对于格子
于是,这个队列中的元素一定是下降的(注意不是优先队列,优先队列是一个堆),使用时直接取front即可。
事实上,在单调队列中存下标即可。
代码
可以直接用STL中的deque(双向队列)。
#include<deque>#include<cstdio>#include<cstring> #include<algorithm>using namespace std;int read(){ int x=0,f=1;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} return x*f;}#define MAXN 500000int pos[MAXN+5],num[MAXN+5];int N,D,K;int f[MAXN+5];bool dp_check(int g){ deque<int> Q; memset(f,0,sizeof f); int Lg=max(1,D-g),Rg=D+g; int Now=0;//Now为现在新加入Q的格子 //printf("%d\n",g); for(int i=1;i<=N;i++) { while(pos[Now]+Lg<=pos[i]) { while(!Q.empty()&&f[Q.back()]<=f[Now]) //注意,!Q.empty一定要写在前面 Q.pop_back(); Q.push_back(Now++);//不一定只放一个 } while(!Q.empty()&&pos[Q.front()]+Rg<pos[i])//把队列前面不需要的pop掉 Q.pop_front(); if(!Q.empty()) f[i]=f[Q.front()]+num[i];//直接取出最前面的 else f[i]=-0x3f3f3f3f;//否则表示到不了这个格子 //printf(" %d\n",f[i]); if(f[i]>=K) return 1;//随时都有可能>=K,而不是只在循环玩后比较f[N]与K } return 0;}int main(){ freopen("jump.in" ,"r", stdin); freopen("jump.out","w",stdout); N=read(),D=read(),K=read(); long long sum=0; for(int i=1;i<=N;i++) { pos[i]=read(),num[i]=read(); if(num[i]>0) sum+=num[i]; } if(sum<K) { printf("-1"); return 0; } int left=0,right=pos[N];//答案的最大值是pos[N],而不是N! while(left<right) { int mid=(left+right)>>1; if(dp_check(mid)) right=mid; else left=mid+1;//mid也不符合条件,所以是mid+1 } printf("%d",right);}
- NOIP2017普及组★跳房子
- [NOIP2017普及组]跳房子
- 【NOIP2017普及组正式赛】跳房子
- NOIP2017跳房子(普及T4)
- 【NOIP2017普及组T4】跳房子-二分答案+DP单调队列优化
- 【NOIP2017】跳房子
- NOIP2017普及组★成绩
- NOIP2017普及组★图书管理员
- NOIP2017普及组★棋盘
- NOIP 2017 普及组 跳房子 jump
- NOIP2017普及组题解
- NOIP2017普及组
- [NOIP2017普及组]棋盘
- 【NOIP2017普及组】棋盘
- NOIP2017普及组题解
- NOIP2017普及组总结
- [NOIP2017普及组]成绩
- [NOIP2017普及组]图书管理员
- Linux中atme,ctime,mtime的区别
- 思路变换
- freemarker语法
- 使用hibernateTemplate执行add方法 出现Write operations are not allowed in read-only mode (FlushMode.MANUAL)
- ios文档网址
- NOIP2017普及组★跳房子
- freemarker配置
- [NOIP2017普及组]T2图书管理员(前导0)
- 我的电路实践
- HHUOJ_1322: 挂盐水
- http 和https
- MVC(javaBean,JSP,Servlet)与MySQL结合例子
- python 基础之字典
- fox浏览器兼容flexbox问题