输入样例1:
5
3 4 3 2 4
输出样例1:
4
输入样例2:
3
4 4 4
输出样例2:
4
输入样例3:
3
1 6 4
输出样例3:
3
解题思路:
从题中得出能量的变化关系:即2*e-arr[i];而要求的是在正值的情况下的e的最小值,所以只要通过二分找出符合条件的值即可。
在遍历数组中的值时,由于每次都是在上一次的能量值翻倍后再减去数组的中的某一值,所以再翻倍时会爆出int的范围,甚至long也会爆,只能用java中的BigInteger类进行相乘。
优化:在相乘时,可以得出当某一时刻的能量值比数组中元素的最大值还要大时,那么后面再相乘时只会越来越大,更不可能出现负值。所以只要某一刻能量比数组中元素大时,可以直接认为后面元素都满足正值条件。
Java代码:(优化前)
import java.io.*;
import java.math.BigInteger;
public class Main {
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
int []arr = new int[n];
String[] split = br.readLine().split(" ");
for(int i = 0; i < n; i++) {
arr[i] = Integer.parseInt(split[i]);
}
int l = 1;
int r = 10000;
while(l < r) {
int mid = l + r >> 1;//二分
boolean tag = true;
BigInteger temp = new BigInteger(mid + "");
int i = 0;
for(i = 0; i < n; i++) {
BigInteger num = temp.multiply(new BigInteger("2")).subtract(new BigInteger(arr[i] + ""));
if(num.compareTo(new BigInteger("0")) < 0) {//出现负值时
tag =false;//标记tag
break;
}else {
temp = num;
}
}
if(tag) r = mid;//说明数够大,没有出现负值,应该缩小,移动右端点
else l = mid + 1;//说明数取的小了,应扩大,移动左端点
}
System.out.println(l);
}
}
Java代码:(优化后)
import java.io.*;
public class Main {
static int []arr;
static int max;
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
arr = new int[n];
String[] split = br.readLine().split(" ");
max = arr[0];
for(int i = 0; i < n; i++) {
arr[i] = Integer.parseInt(split[i]);
max = arr[i] > max ? arr[i] : max;//找出数组中的最大值
}
int l = 1, r = 100000;
while(l < r) {
int mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
System.out.println(r);
}
public static boolean check(int e) {//优化检查函数
for(int i = 0; i < arr.length; i++) {
e = e * 2 - arr[i];
if(e < 0)return false;
if(e >= max) return true;//当某一刻能量比数组中能量的最大值还要大是,不管之后数组值如何,都不会变为负值
}
return true;
}
}