机器人跳跃问题(字节跳动2019春招)

题目链接:点击这里

机器人跳跃问题(字节跳动2019春招)_第1张图片
机器人跳跃问题(字节跳动2019春招)_第2张图片
机器人跳跃问题(字节跳动2019春招)_第3张图片

思路:

H ( k + 1 ) > E H(k+1) > E H(k+1)>E 时,机器人就失去 H ( k + 1 ) − E H(k+1) - E H(k+1)E 的能量值,即 E − ( H ( k + 1 ) − E ) = 2 E − H ( k + 1 ) E-(H(k+1)-E) = 2E-H(k+1) E(H(k+1)E)=2EH(k+1)

否则,将得到 E − H ( k + 1 ) E - H(k+1) EH(k+1) 的能量值,即 E + ( E − H ( k + 1 ) ) = 2 E − H ( k + 1 ) E+(E-H(k+1)) = 2E-H(k+1) E+(EH(k+1))=2EH(k+1)

一个直观感觉,初始能量越大就越能完成游戏,用数学归纳法可以证明初始能量具有单调性。因此,我们可以对初始能量进行二分去寻找答案。

在check()函数中,如果我们仅仅依靠上述公式去递推判断,是会爆掉 int 和 long long 的,因为能量值是呈 2 2 2 的指数级增长的。

比较巧妙的地方是,可以挖掘出下面这一条性质去提前结束循环防止溢出。

对于某个当前能量值 E   ( E ≥ m a x H ) E\ (E \geq maxH) E (EmaxH),那么它下一点的能量值为 2 E − H ( i ) = E + E − H ( i ) ≥ E 2E-H(i) = E+E-H(i) \geq E 2EH(i)=E+EH(i)E

得出结论:如果某个能量值已经大于等于 m a x H maxH maxH 了,那么它后面的能量值都是递增的,不会有减少的了。故有了该性质,就不用去挨个循环递推了。

AC代码如下:

#include
#include
#include
#include

using namespace std;

const int N = 100010;

int n;
int h[N];

bool check(int e)
{
    for(int i = 1; i <= n; i++)
    {
        e = 2 * e - h[i];
        if(e >= 1e5)    return true;
        if(e < 0)   return false;
    }
    return true;
}

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &h[i]);
    
    int l = 0, r = 1e5;
    while(l < r)
    {
        int mid = l + r >> 1;
        if(check(mid))  r = mid;
        else    l = mid + 1;
    }
    
    printf("%d\n", r);
    
    return 0;
}

你可能感兴趣的:(二分)