二分贪心 湖南多校对抗赛4——J - Let Me See See! Gym - 323915J

" 你看这个彬彬 , 还没喝几罐 , 就醉了 , 真的太逊了 . "

" 这个彬彬就是逊啦 ! "

" 听你这么说 , 你很勇哦 ? "

" 开玩笑 , 我超勇的好不好 , 我超会喝的啦 . "

因为阿伟超会喝 , 所以杰哥给阿伟出了一道这样的题目 :

一条数轴上有 n 个点 , 坐标分别为 x1 , x2 , … , xn , 你要选择其中 m 个点 , 使得任意两个点之间的最小距离最大 . 设数轴上两个点的坐标分别为 xi 和 xj , 那么这两个点的距离定义为 |xi - xj| .

杰哥说如果阿伟把这道题做出来就带他转大人 , 还会康很多好康的 . 你的任务是帮阿伟把这道题做出来 . 如果没有做出来 , 也没有关系 , 如果做出来了 , 等下你可以去超商买一些好吃的哦 !

Input
第一行包含两个整数 n 和 m (2 ≤ m ≤ n ≤ 105) , 含义如上所述 . 两个数之间用空格隔开 .

第二行为 n 个用空格隔开的整数,表示坐标 xi(0 ≤ xi ≤ 109) ,

Output
输出共一行 1 个数 , 表示答案 .

Example
Input
5 3
1 2 8 4 9
Output
3

要点:
计算机的思维和人的思维是不同的,它拿了个检测要求去凑答案,不是去找最短计数:
二分的mid是当前认为的最短距离,判断的是取点的个数是否不少于要求,是就可以再增加认为的距离,不是就减少认为的距离,直到mid确定为止
二分下贪心,所谓的“下”指的就是二分的关键:判断函数是关键
在内部贪心思路,局部最优,看当前两点距离是不是不小于猜测距离,是则状态为起点是该点,计数,否则删该点,即跳到下一个不计数。
是看下一个点到上一个点,最好不要看上一个点能延伸下去的那个点,这样会均匀地走。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<vector>
#include<map>
#include<set>
#include<ctype.h>
#include<stack>
#include<queue>
#ifdef LOCAL
FILE*FP=freopen("text.in","r",stdin);
//FILE*fp=freopen("text.out","w",stdout);
#endif
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define _forplus(i,a,b) for( register int i=(a); i<=(b); i++)
#define _forsub(i,a,b) for( register int i=(a); i>=(b); i--)
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())
#define INF 0x3f3f3f3f
#define N 100005
const double pi=acos(-1);
int a[N],n,res; 
bool bl(int now){
	int cnt=1;
	int tem=1;
	_forplus(i,2,n){
		if(a[i]-a[tem]>=now){
			cnt++;
			tem=i;
		}
	}
	if(cnt>=res)return true;
	else return false;
}
int main(){
	scanf("%d%d",&n,&res);
	_forplus(i,1,n){
		scanf("%d",&a[i]);
	}
	sort(a+1,a+n+1);
	int l=0,r=a[n]-a[1],mid,ans;
	while(l<=r){
		mid=(l+r)/2;
		if(bl(mid)){ 
			ans=mid;
			l=mid+1;
		}else{
			r=mid-1;
		} 
	}
	printf("%d\n",ans);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值