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

    技术2022-07-12  78

    题目链接:点击这里

    思路:

    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<iostream> #include<cstdio> #include<cstring> #include<algorithm> 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; }
    Processed: 0.011, SQL: 9