• 洛谷 P2678 跳石头


    洛谷 P2678 跳石头

    题目背景

    一年一度的“跳石头”比赛又要开始了!


    题目描述

    这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 (N) 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。

    为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 (M) 块岩石(不能移走起点和终点的岩石)。


    输入输出格式

    输入格式:

    第一行包含三个整数 (L,N,M),分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证 (L geq 1)(N geq M geq 0)

    接下来 (N) 行,每行一个整数,第 (i) 行的整数 (D_i( 0 < D_i < L)), 表示第 (i) 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。

    输出格式:

    一个整数,即最短跳跃距离的最大值。


    输入输出样例

    输入样例#1:

    25 5 2
    2
    11
    14
    17
    21

    输出样例#1:

    4


    说明

    输入输出样例 1 说明:将与起点距离为 (2)(14) 的两个岩石移走后,最短的跳跃距离为 (4)(从与起点距离 (17) 的岩石跳到距离 (21) 的岩石,或者从距离 (21) 的岩石跳到终点)。

    另:对于 (20\%)的数据,(0 ≤ M ≤ N ≤ 10)

    对于(50\%)的数据,(0 ≤ M ≤ N ≤ 100)

    对于 (100\%)的数据,(0 ≤ M ≤ N ≤ 50,000),(1 ≤ L ≤ 1,000,000,000)


    思路

    数据范围太大了,我们很容易想到暴力过不去
    但是我们看到了一句话

    一个整数,即最短跳跃距离的最大值。

    又很容易的想到,可以用二分!
    没错,就用二分,但是二分的条件是什么呢?

    一个是有界,一个是单调

    那么这个题为什么能二分呢??看一下来自dalao的讲解

    二分答案应该是在一个单调闭区间上进行的。也就是说,二分答案最后得到的答案应该是一个确定值,而不是像搜索那样会出现多解。二分一般用来解决最优解问题。刚才我们说单调性,那么这个单调性应该体现在哪里呢?

    可以这样想,在一个区间上,有很多数,这些数可能是我们这些问题的解,换句话说,这里有很多不合法的解,也有很多合法的解。我们只考虑合法解,并称之为可行解。考虑所有可行解,我们肯定是要从这些可行解中找到一个最好的作为我们的答案, 这个答案我们称之为最优解。

    最优解一定可行,但可行解不一定最优。我们假设整个序列具有单调性,且一个数x为可行解,那么一般的,所有的x'(x'<x)都是可行解。并且,如果有一个数y是非法解,那么一般的,所有的y'(y'>y)都是非法解。

    那么什么时候适用二分答案呢?注意到题面:使得选手们在比赛过程中的最短跳跃距离尽可能长。如果题目规定了有“最大值最小”或者“最小值最大”的东西,那么这个东西应该就满足二分答案的有界性(显然)和单调性(能看出来)。

    所以我们就可以二分啦,不过不要忘记,第n+1个点才是终点!!


    代码

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #define N 500010
    #define INF 0x3f3f3f3f
    using namespace std;
    
    int l,n,m;
    int a[N]; 
    int lefted,r,mid;
    int ans;
    
    inline int read(){
    	char c=getchar();int x=0,f=1;
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9')x=x*10+c-48,c=getchar();
    	return x*f;
    }
    
    bool pd(int x){
    	int s=0;
    	int i=0;
    	int pre=0;
    	while(i<n+1){/*不能忘记是n+1,因为n+1个点才是终点*/
    		i++;
    		if(a[i]-a[pre]<x){
    			s++;
    		}
    		else pre=i;
    	}
    	if(s>m)return 0; 
    	else return 1;
    }
    
    int main(){
    	freopen("stone.in","r",stdin);
    	freopen("stone.out","w",stdout);
    	l=read(),n=read(),m=read();
    	for(int i=1;i<=n;i++)a[i]=read();
    	a[n+1]=l;
    	//二分啦! 
    	lefted=1,r=l;
    	while(lefted<=r){
    		mid=(lefted+r)/2;
    		if(pd(mid)){
    			ans=mid;
    			lefted=mid+1;
    		}else{
    			r=mid-1;
    		}
    	} 
    	cout<<ans<<"
    ";
    	fclose(stdin);
    	fclose(stdout);	
    	return 0;
    }
    
  • 相关阅读:
    计算机图形学——几何变换的数学基础
    算法设计与分析——多边形游戏(动态规划)
    算法设计与分析——凸多边形最优三角剖分(动态规划)
    计算机图形学——反走样
    Android 5.0 API
    Android 6.0 API
    Android 7.0 新增功能和api
    Android 8.0 功能和 API
    Android P 功能和 API
    解决华为手机无法输出Debug级别log的问题
  • 原文地址:https://www.cnblogs.com/loceaner/p/10792991.html
Copyright © 2020-2023  润新知