AcWing 730. 机器人跳跃问题——有些关于二分的个人理解,希望大家来帮忙指点一二【简单的二分,头一回见到暴long long的题目。。。】
原题链接
中等
//二分数据的单调性与二段性(以下为个人理解,欢迎各位来帮忙指点一二):
//要二分的数据要保证按照某种顺序排好即可满足单调性,大多为从大到小或从小到大
//即大多为数列中的数值关于数列下标单调,i <= j -> a[i] <= a[j]
//但我个人感觉数列不按从大到小或从小到大的顺序排列,只要满足二段性,也可以二分
//即我个人观点认为,二分的二段性的重要性远大于单调性。
//二段性则是说排好的数列中有一个位置上的值可作为某种判断方法的分界点,将整个
//排好的数列一分为二
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
typedef long long LL;
int h[N];
int n;
int merge(int l, int r)
{
while(l < r)
{
int mid = l + r >> 1;
//cout << mid << endl;
LL e = (LL)mid;//写了“e>1e5”后,e用LL或int都可以
//不写的话。。。都会暴的。。。
for(int i = 1; i <= n; i ++)
{
//if(e >= (LL)h[i]) e += e - (LL)h[i];
//else e -= (LL)h[i] - e;
e = 2 * e - (LL)h[i];//以上两行注释掉的代码可以化简为本行代码
//从上一行代码可知,每一轮循环都会使得e最多翻一倍,
//因此e是可能会暴long long的,暴LL后数值会失真,甚至便为负数
if(e < 0 || e > 1e5) break;//“e>1e5”就是为了防止暴long long
//由于每一个h[i]都是最大为1e5,因此当e超过1e5之后,就一定能
//到达终点,因此没必要再向后循环了
}
if(e < 0) l = mid + 1;
else r = mid;
}
return l;
}
int main()
{
cin >> n;
//int l = 0, r = 0;
for(int i = 1; i <= n; i ++)
{
scanf("%d", &h[i]);
//r = max(r, h[i]);
}
int l = 0, r = 1e5;
cout << merge(l, r) << endl;
return 0;
}