我是一个正在学习算法的小菜鸡,最近看到一句话:“%尽普天大佬,A遍天下水题”,感觉好有意思【😂】,虽然不明白前面一句话的意思,懂得友友评论区告诉我一下呗。
好了言归正传,我想谈一下二分的条件限制问题,我们知道在传统的二分查找的时候,mid比较只有三种情况:大了,小了,正确;但是在这里我们比较时只有两种结果:满足,不满足;我们的目的是在满足里面找到一个最满足的,这时候在移动的时候我们就要慎重考虑一下了,因为一旦移动过了感觉不是很好回溯,然后需要我们考虑的有以下三个地方:left (<?<=) right ; left = (mid?mid+1) ;right = (mid ?mid -1)。
首先我们的while循环靠left和right来结束,如果用<=那么,后面移动的是后都要带上1, 例如在此题的情况:因为当le==right时候且这个数正是合理的,若right=mid,那么会一直循环无法结束。但有时候他会跨过最优解,向左或右多走一个,这就需要在le==ri的时候再判断一边了,若是最优解在右边,最后返回le;反之就返回ri。不是很好解释,大家拿笔试试就清晰了。
当使用 le<ri 时候,那就不用考虑相等的时候了,在以此题为例,只需ri=mid,来维持已知的最优解而无需跨越,只需le=mid+1 来缩短区间,最后一定会收敛到le==right ,所以经过测试,这么写也是满分。这题因为是从最右边向左收敛,若换成其他的题要从左向右收敛,那么我想也是同样的道理。
好了如果大家觉得对你有用的话还请点个赞再走哦👍👍👍
#include<bits/stdc++.h>
using namespace std;
int n,m,k;
vector<pair<int,int>>vec;
int judge(int a){
int sour=m;
for(int i=vec.size()-1; sour>=0&& vec[i].first>a ;i--){
sour-=(vec[i].first-a)*vec[i].second;
}
return sour;
}
int main() {
cin>>n>>m>>k;
int a,b;
for(int i=0;i<n;i++){
cin>>a>>b;
vec.push_back(make_pair(a,b));
}
sort(vec.begin(),vec.end());
int le=k,ri=(*--vec.end()).first,mid;
int temp;
while (le<=ri)
{
mid=(le+ri)/2;
temp=judge(mid);
if(temp>=0){
ri=mid-1;
}
else
le=mid+1;
}
cout<<le<<'\n';
return 0;
}