AcWing 730. 机器人跳跃问题 题解

题目

AcWing 730. 机器人跳跃问题 题解_第1张图片
AcWing 730. 机器人跳跃问题 题解_第2张图片


思路:有单调性、二分性,记得用二分

  • 我们发现不管机器人在第 k k k个位置处的能量E与第 k + 1 k+1 k+1个位置处的高度 H ( k + 1 ) H(k+1) H(k+1)有何大小关系,递推式都是 E k + 1 = 2 × E k − H ( k + 1 ) E_{k+1}=2\times E_{k}-H(k+1) Ek+1=2×EkH(k+1)
  • 在整个过程中,能量 E E E都不能小于 0 0 0才算成功,则在任何位置处 E k + 1 = 2 × E k − H ( k + 1 ) ≥ 0 E_{k+1}=2\times E_{k}-H(k+1)≥0 Ek+1=2×EkH(k+1)0都要成立
  • 如果初始时 E = E 0 E=E_{0} E=E0可以成立,那么 E = E 1 > E 0 E=E_{1}>E_{0} E=E1>E0时,仍然会成立。
    这体现了 E E E的取值满足一个单调性(单调增)和二分性,即存在一个边界,边界的一边不满足条件,边界的另一边满足条件
    上述单调性的证明:
    在这里插入图片描述
    因此可以使用二分法,在 E E E的所有可能取值中,找到 E ≥ E 0 E≥E_{0} EE0的边界( E 0 E_{0} E0为符合条件的最小值)
  • 二分的 c h e c k check check函数怎么写呢?
    对每一个 E E E初值,检验其在每个建筑时的能量,如果都大于0,则符合条件
    那其实也是没有必要遍历所有的建筑只要有某处的能量值大于所有建筑中的最高高度,后面就都满足条件了
    假设最高的建筑高为 m a x h maxh maxh,某处的能量 E ≥ m a x h E≥maxh Emaxh
    则在它后面一个建筑的能量为
    E n e x t = 2 × E − h n e x t E_{next}=2\times E-h_{next} Enext=2×Ehnext
    = E + E − h n e x t =E+E-h_{next} =E+Ehnext
    ≥ E + m a x h − h n e x t ≥E+maxh-h_{next} E+maxhhnext
    ≥ E ≥E E
    ≥ m a x h ≥maxh maxh
    即从这个建筑开始,后面的能量都将 ≥ m a x h ≥maxh maxh,不会有小于 0 0 0的情况出现。
  • 为什么要在 0 0 0 m a x h maxh maxh 之间进行二分?
    由上面的证明可知,如果 E E E初值取 m a x h maxh maxh,则所有建筑处的能量必然满足条件,且能量都 ≥ m a x h ≥maxh maxh,我们要求的是“最小”,这是绰绰有余的上界,因此可以作为二分上界。
    如果初始情况为 0 0 0,这是一种最小的极端下界,也即假定所有建筑的高度也为 0 0 0,这种情况才能符合条件,但是往往所有建筑物的高度会比这个大,所以可以作为二分下界

代码

#include
#include
using namespace std;
const int N=1e5+10;
int h[N];
int n,Max=-1;
bool check(int e)  //传过来的e就是第0个建筑处的初值
{                  //进入循环就直接从第一个建筑处的能量开始判断了
    for(int i=1;i<=n;i++)
    {
        e=2*e-h[i];   
        if(e>=Max) return true;  //过程中有点的能量大于建筑物高度的最大值了,就不用往后再递推判断了,一定符合条件的
        if(e<0) return false;      //过程中如果有点的能量<0,则不符合条件
    }
    return true;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&h[i]);
        Max=max(Max,h[i]);    //找到所有建筑高度的最大值
    }
    int l=0,r=Max; //E要取最小满足条件的,可以想到在0和建筑物高度最大值之间,但其实更保险的可以取100000
    while(l<r)   //二分出E的结果
    {
        int mid=l+r>>1;
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    printf("%d",l);
    return 0;
}

你可能感兴趣的:(#,蓝桥杯,code,刷题,总结&记录,二分)