借书【二分】

借书【二分】

题目描述

DilhaoDilhao一共有nn本教科书,每本教科书都有一个难度值,他每次出题的时候都会从其中挑两本教科书作为借鉴,如果这两本书的难度相差越大,DilhaoDilhao出的题就会越复杂,也就是说,一道题的复杂程度等于两本书难度差的绝对值。

这次轮到ldxxxldxxx出题啦,他想要管DilhaoDilhao借mm本书作为参考去出题,DilhaoDilhao想知道,如果ldxxxldxxx在DilhaoDilhao给出的mm本书里挑选难度相差最小的两本书出题,那么ldxxxldxxx出的题复杂程度最大是多少?

输入格式

第一行是nn和mm。

接下来的nn行,每行一个整数aiai表示第ii本书的难度。

输入格式

一个整数为ldxxxldxxx出的题复杂程度的最大值。

输入样例

6 3

5

7

1

17

13

10

输出样例

7

样例解释

DilhaoDilhao给了ldxxxldxxx难度为1,10,171,10,17的三本书,ldxxxldxxx挑选难度为1010和1717的两本书,出题复杂度为77;

如果DilhaoDilhao给出其他任何三本书,其中的两本书难度差的最小值都小于77,所以ldxxxldxxx出题最大的复杂程度为77。

数据说明

对于 30%30%的数据: 2≤n≤202≤n≤20;

对于 60%60%的数据: 2≤n≤10002≤n≤1000;

对于 100%100%的数据: 2≤n≤1000002≤n≤100000, 2≤m≤n2≤m≤n, 0≤ai≤10000000000≤ai≤1000000000。


思路分析

  • 题目很好理解,一堆书中给你m本书,选出这m本书中两本书难度差最小的值作为出题的复杂程度,最后输出最大复杂程度,显然是一道最小值最大化的问题,就需要用到二分

二分从哪里入手

  • 首先可以明确的是这题要对差值处理,考虑到我们要选m本中的最小差值,那么我们完全可以将原数组排序后处理为差分数组,然后两个数的差值从前往后加即可
  • 二分过程:
    • 最大的最小差值为边界,然后判断右边界(显然右边界最大)是否成立,成立即为最优答案,否则再判断mid,进行区间缩小
    • 判断条件:我们只需要看以该值作为最小差值是否能选出m个数即可(即m-1个差值)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
inline int read(){
   int s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
const int maxn=1e5+5;
int n,m,a[maxn],cf[maxn];
int Max=0;
void Init(){
	n = read(),m = read();   
    for(int i=1;i<=n;i++){
        a[i] = read();
        Max=max(Max,a[i]);
    }
    sort(a+1,a+n+1);
    for(int i=1;i<n;i++){
        cf[i]=a[i+1]-a[i];//cf差分数组
    }
}
bool check(int x){ //x为二分过程中枚举的差值
    int cnt=0,ch=0;//ch当前的最大差值
    for(int i=1;i<n;i++){
        ch+=cf[i];
        if(ch>=x){//找到一对差值大于x
            cnt++,ch=0;//从下个位置找下一对
        }
    }
    if(cnt>=m-1)return true; //能够找出m-1个差值
    return false;
}
int main(){
    n = read(),m = read();   
    for(int i=1;i<=n;i++){
        a[i] = read();
        Max=max(Max,a[i]);
    }
    sort(a+1,a+n+1);
    for(int i=1;i<n;i++){
        cf[i]=a[i+1]-a[i];//cf差分数组
    }
    int l=0,r=Max;
	while(l<=r){
        if(r-l==1){ //区间不能再缩小
            if(check(r)==true) //右边界最大,判断是否可以作为答案
                l=r;
            break;
        }
        int mid=(l+r)/2;
        if(check(mid)==true) //向右缩小空间,继续寻找更优解
            l=mid;
        else r=mid; //中间值太大,向右缩小区间
    }
    printf("%d
",l);//左边界最小,一定符合答案
    return 0;
}

发量成功减1%

原文地址:https://www.cnblogs.com/hhhhalo/p/13251356.html