0 题目来源

acwing

1 涉及到的知识点

二分

一些技巧:
在遇到题目时,可以对各种算法(二分、dp、贪心等等)进行尝试,看哪种算法最为合适。
多考虑边界情况(最大数字、最小数字)

2 题目描述

机器人正在玩一个古老的基于 DOS 的游戏。
游戏中有N+1座建筑——从0到N编号,从左到右排列。
编号为0的建筑高度为0个单位,编号为i的建筑高度为H(i)个单位。
起初,机器人在编号为0的建筑处。
每一步,它跳到下一个(右边)建筑。
假设机器人在第k个建筑,且它现在的能量值是E,下一步它将跳到第k+1个建筑。
如果H(k+1)>E,那么机器人就失去H(k+1)−E的能量值,否则它将得到E−H(k+1)的能量值。
游戏目标是到达第N个建筑,在这个过程中能量值不能为负数个单位。
现在的问题是机器人至少以多少能量值开始游戏,才可以保证成功完成游戏?

3 输入输出

输入格式:
第一行输入整数N。
第二行是N个空格分隔的整数,H(1),H(2),…,H(N)代表建筑物的高度。
输出格式:
输出一个整数,表示所需的最少单位的初始能量值上取整后的结果。
数据范围:
[题解]机器人跳跃问题 - 图1

4 样例

输入样例1:
5
3 4 3 2 4
输出样例1:
4
输入样例2:
3
4 4 4
输出样例2:
4
输入样例3:
3
1 6 4
输出样例3:
3

5 思路

本题要求给定一个初始能量值E,使得从第一个建筑开始跳跃,跳到最后,能量仍然大于等于0。
明显,如果初始能量E非常大,则最后的能量一定大于0(符合条件);而如果初始能量E很小,则最后的能量很有可能小于0。即本题的条件具有二段性,我们要求的就是符合二段性的临界点的值,即符合最后剩余能量大于等于0的下界值。
根据上面的分析,我们可以使用binarysearch_lower_bound模板对问题进行解决。
根据分析,在从第i个建筑跳到第i+1个建筑时,能量![](https://cdn.nlark.com/yuque/__latex/269578d30b067a684977465ee71e32ff.svg#card=math&code=E
%7Bi%2B1%7D%3DEi%2B%28E_i-H%7Bi%2B1%7D%29%3D2Ei-H%7Bi%2B1%7D&id=Ggx8i)。也即能量E几乎在翻倍(以[题解]机器人跳跃问题 - 图2的速度)增长,这样大的数据是不可能在int或者long long中存储的。观察可以看出,当E大于等于最高的建筑物时,E就不可能再减小了,此时的初始E一定符合条件。我们可以根据这个条件进行剪枝。
综上,本题可以使用二分法进行解决。

6 代码

  1. #include<iostream>
  2. #include<cstdio>
  3. using namespace std;
  4. int h[100010];
  5. int n;
  6. int maxn,minn=100001;
  7. int binary_search_lower()
  8. {
  9. int l = 1, r = 100000;
  10. int mid;
  11. while (r > l)
  12. {
  13. mid = (l + r) / 2;
  14. int e = mid;
  15. int flag = 0;
  16. for(int i=1;i<=n;i++)
  17. {
  18. e=2*e-h[i];
  19. if(e<0)
  20. {
  21. flag=1;
  22. break;
  23. }
  24. if(e>=maxn)//剪掉E>=max
  25. {
  26. flag=0;
  27. break;
  28. }
  29. }
  30. if (!flag)
  31. r = mid;
  32. else
  33. l = mid + 1;
  34. }
  35. return l;
  36. }
  37. int main()
  38. {
  39. cin >> n;
  40. for (int i = 1; i <= n; i++)
  41. {
  42. scanf("%d", &h[i]);
  43. if(h[i]>maxn)
  44. maxn=h[i];
  45. if(h[i]<minn)
  46. minn=h[i];
  47. }
  48. cout << binary_search_lower();
  49. return 0;
  50. }