题意:
一条直线上有a个瓶盖,要选取b个瓶盖,使得选取的瓶盖中最近距离的两个瓶盖距离在所有可行方案中最大。
题目条件:
(b<=a<=100000)
分析:
一开始没看清题意,以为是要找到某个方案中,所有相邻瓶盖距离都最大,然后求这些距离中的最大距离,然后就各种想不通,最后才发现是读了个假题意。。。正确理解就是求所有可行方案中,各个方案的最小距离的最大值,那么就是最小值最大化问题。首先需要对输入的瓶盖坐标排序,然后就是二分边界确定,最小可能不可能小于0,最大不可能大于坐标最大的瓶盖与坐标最小的瓶盖的距离差值,然后就是写check函数,以mid作为该方案中瓶盖之间距离的最小值,传入mid(即估计的答案),利用贪心策略,选择出所有相邻距离大于等于mid的瓶盖,这样就可以尽可能选择多的瓶盖,然后对于可选瓶盖数大于要求选的b个瓶盖数的方案,实际选的过程可以只选b个,多的不选,这样也算是符合题意的方案,这样贪心的结果就是可以不遗漏的枚举出所有可行方案,然后就是利用二分答案,来让最小值最大化,对于二分选择的逻辑就是,如果最后得到的cnt>=b,那么我们希望所有相邻瓶盖距离都尽可能的大,这样瓶盖之间最小的距离也就尽可能的大了,这也是贪心策略,所以我们就需要让cnt变小,使它趋近于b,那么我们假定的mid,就需要变大,这样瓶盖之间距离大于等于mid的个数就会变少,也就是cnt变小。最后还是需要注意二分的写法。
主要代码
int a,b;
bool check(vector<int>& d,int ans){
int cnt=1,pos=0;
for(int i=1;i<a;i++){
if(d[i]-d[pos]>=ans){
cnt++;
pos=i;
}
}
return cnt>=b;
}
void solve(){
vector<int> d(a);
for(int i=0;i<a;i++)
cin>>d[i];
if(b<=1){
cout<<"0\n";
return;
}
sort(ALL(d));
int l=0,r=d[a-1]-d[0];
while(l<r){
int mid=(l+r+1)>>1;
if(check(d,mid))
l=mid;
else
r=mid-1;
}
cout<<l<<endl;
}