POJ 3258 River Hopscotch

本来以为自己二分枚举答案求可行解已经比较厉害了,谁知上来就被卡两个小时。。

这题吧。。确实很恶心,边界条件很难控制,许多AC的人都不能证明自己代码的正确性。

先贴代码:

#include<stdio.h>
#include<algorithm>
typedef long long ll;
using namespace std;
ll n,m,L,a[100010];
bool bi(ll x){
	ll i,cnt=0,now=0;
	for(i=1;i<=n;i++){
		if(a[i]-a[now]<=x)cnt++;
		else    now=i;
	}
	if(L-a[now]<x)return 0;
	return cnt<=m;
}
int main(){
	ll i,l,r,mi;
	while(~scanf("%lld%lld%lld",&L,&n,&m)){
		l=0;r=L;
		for(i=1;i<=n;i++)
		    scanf("%lld",&a[i]),
		    r+=a[i];
        sort(a,a+n+1);
		while(l<r){
			mi=l+r>>1;
			if(bi(mi))l=mi+1;
			else      r=mi;
		}
		printf("%lld\n",r);
	}
	return 0;
}



 

二分的就是最小的步长。

这题的关键点在于在取出M个石头之后,牛是要把所有石头都跳一遍的。

那么想象一下,如果规定了最短距离的步长,应该是什么样的情况。

假设牛在now这个石头上,如果a[now+1]-a[now]>=x ,那么now+1这个石头是肯定不会跳的,

那么接下来备选的石头一定是now+2,now+3...直到a[i]-a[now]<x。

那么对于j这个石头来说,是一定要跳到a[j]的,因为当固定了步长x的时候,应该尽量减少去掉的石头数,

这样使得x能尽量大。

所以下一步就应该从a[j]开始枚举,尽量往下跳,

但是对于最后一个石头来说,如果L-a[now]<x 那么说明在这次跳跃过程中,最小步长是L-a[now]而不是x,

因为其他跳跃过程都是按照a[i]-a[now]>x跳的,所以应该减小x,使得L-a[now]>=x 而合法,

所以return 0 使得r=mi。

最后输出。

 

你可能感兴趣的:(二分枚举答案)