洛谷篇p2678跳石头

原题链接:跳石头

二分答案:个人理解就是将答案的可能区间写出,在用二分查找去寻找满足题意的答案

        以跳石头为例,题目叫我们取最短跳跃距离的最大值,这个最短跳跃距离的可能性有哪些呢?这个距离的范围是[1,L/(n-m+1)],这个右边界是怎么来的?

        因为这个区间最开始只有[1,L]这一个范围,每加一个石头就多一个范围,每去一个石头就少一个范围,假设石头分布均匀那就是L/(n-m+1),如果不均匀,范围就有2种情况,比L/(n-m+1)大,不是最短距离,比L/(n-m+1)小,是最短距离,所以不存在比L/(n-m+1)更大的最短距离.当然在写二分的过程不用考虑这么多,直接将L作为右边界即可,因为不满足会被二分掉,只是时间会长一点.(我这里测出来,只快了2ms,主要二分本来就o(logn)

int i=0,j=l/(n-m+1);
	while(i+1!=j){
		int mid=i+j>>1;
		if(check(mid)) i=mid;
		else j=mid;
	}

Ok,我们找到了范围,这里mid就是我们假设的答案,我们要去判断这个mid是不是真正的答案,此题条件就是最多取石头数,那怎么和mid联系起来呢?

|____|____|____|____|____|____|,这是一个石头均匀的图,每段长度为mid,但一般情况石头是随机分布的,石头有可能在左边和右边.

在左边说明这个石头比我们最短距离还短,换句话说就是这个石头应该被去掉.

在右边说明这个石头比我们最短距离长,不用管它,直接去看下一个石头.

int check(int x){
	int res=0,now=0;//res记录取的石头数目,now记录现在的位置
	for(int i=1;i<=n+1;i++){
		if(a[i]-a[now]<x) res++;//在左边,去掉,res++;
		else now=i;//在右边,直接跳过,去判断这个石头和下一个石头的距离是否满足小于x
	}
	return res<=m;
    //如果假设的答案去掉的石头小于等于真正要去掉的石头说明,最短距离小了,要变大
    //反之最短距离大了,要变小
}

这里有个细节,循环的结束是n+1,为什么呢?因为最后还有一个边界L.

#include <iostream>

using namespace std;

int l,n,m;
const int N=5e4+10;
int a[N];

int check(int x){
	int res=0,now=0;
	for(int i=1;i<=n+1;i++){
		if(a[i]-a[now]<x) res++;
		else now=i;
	}
	return res<=m;
}

int main(){
	scanf("%d%d%d",&l,&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	a[n+1]=l;//右边界
	int i=0,j=l+1;
	while(i+1!=j){
		int mid=i+j>>1;
		if(check(mid)) i=mid;
		else j=mid;
	}
	printf("%d",i);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值