思路:
- 由题意可以推出从当前位置跳到下一个位置时,下一个位置的能量值一定为: 2 ∗ E 当 前 − H 下 一 位 置 2*E_{当前}-H_{下一位置} 2∗E当前−H下一位置
- 由简单的数学归纳可以知道,当 E 0 E_0 E0 满足题意的最小初始能量时,任何大于 E 0 E_0 E0 的初始能量也满足题意,任何小于 E 0 E_0 E0 的初始能量就不再满足题意了
- 从上面的结论可以看出具有二段性,其中二段性的分界点即为满足题意的最小初始能量 E 0 E_0 E0,因此该题可以用二分法
- 二段性:左半段的初始E无法让机器人每次跳跃的位置的能量 > 0,右半段的初始E可以让机器人每次跳跃的位置能量 >= 0
- 分界点:最小的初始E能让机器人每次跳跃的位置能量 >= 0
public class Main {
int N;
int[] H;
Scanner s = new Scanner(System.in);
void run() {
N = s.nextInt();
H = new int[N + 1];
for (int i = 1; i <= N; i++) {
H[i] = s.nextInt();
}
int l = 0, r = 100000;
while (l < r) {
int mid = (r + l) / 2;
if (isValid(mid)) r = mid;
else l = mid + 1;
}
System.out.println(r);
}
boolean isValid(int e) {
BigInteger bi = new BigInteger(String.valueOf(e));
for (int i = 1; i < H.length; i++) {
bi = bi.multiply(new BigInteger(String.valueOf(2)));
bi = bi.subtract(new BigInteger(String.valueOf(H[i])));
if (bi.compareTo(new BigInteger(String.valueOf(0))) < 0) return false;
}
return true;
}
public static void main(String[] args) {
new Main().run();
}
}
细节问题:
对于isValid方法,如果直接使用e = 2 * e - H[i]很可能会爆int(long也不行),所以这里使用了大数来处理
优化:
只要初始能量 e >= H[i] 的最大可能高度,由递推式子 2 ∗ E 当 前 − H 下 一 位 置 2*E_{当前}-H_{下一位置} 2∗E当前−H下一位置 可以推出其后续的每次跳跃的位置的能量一定 > 0,所以该条件下就直接return ture,不用再继续递推导致爆int
boolean isValid(int e) {
for (int i = 1; i < H.length; i++) {
e = 2 * e - H[i];
// 如果不加该判断会爆int
if(e >= 1e5) return true;
if (e < 0) return false;
}
return true;
}