本题是一道典型的最小值最大化的题目
在这一道题目中,已有一串从小到大的有序数组,从数组中任选C个元素(C已经确定),求这些元素两两之间的距离,找出最小的距离,问在所有选法当中,最小距离最大是多少?
首先按照二分答案的常规思路,我们确定了最小距离的取值范围,按照朴素方法,就是从大到小一一枚举区间内所有的值x,并判断值x是否符合题目条件,即在最小距离的情况下,是否能从数组中选出恰好C个元素,从这里我们可以发现,最小距离越大(小),意味着我们按照这个标准从数组中最多可以选出的元素越少(多),假设我们枚举到的最小距离是x,按照该标准从数组中最多可以选取y个元素,1.当y > C时说明x可以更大一些 2.当y < C时说明x太大了使我们不论怎么选都选不够C个元素 3.当y = C时说明x可以让我们恰好选到C个元素,但也有可能比x更大的值也能让我们选到C个元素。
从而我们可以总结出判断条件(该条件可以将最小距离的取值范围分成左右两个部分),假设我们的最终答案是q,每轮二分枚举到的数值为x:
1.当x对应的y值(以x为最小距离,从数组中可以取到的最多元素个数y)小于等于C时,意味着x值是小于等于q的,因此应该让l = x;
2.当x对应的y值大于C时,意味着x值是大于q的,因此应该让r = x - 1。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e5 + 10;
int a[N];
int n, c;
bool check(int mid)// 3
{
int res = a[0], cnt = 1;
for(int i = 1; i < n; i ++)
{
if(a[i] >= res + mid)
{
res = a[i];
cnt ++;
}
else
{
continue;
}
}
if(cnt >= c) return true;
else if(cnt < c) return false;
}
int bsearch(int l, int r)
{
while(l < r)
{
int mid = l + r + 1 >> 1;
//cout << l << " " << r << " " << mid << endl;
if(check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
int main()
{
cin >> n >> c;
int l = 1e9 + 10, r = 0;
for(int i = 0; i < n; i ++)
{
scanf("%d", &a[i]);
}
sort(a, a + n);
for(int i = 0; i < n; i ++)
{
if(i > 0)
{
l = min(a[i] - a[i - 1], l);
r = max(a[i] - a[0], r);
}
}
int ans = bsearch(l, r);
cout << ans << endl;
return 0;
}