[蓝桥杯 2024 国 B] 立定跳远
问题描述
在运动会上,小明从数轴的原点开始向正方向立定跳远。项目设置了 n 个检查点 a1,a2,...,an且 ai≥ai−1>0。小明必须先后跳跃到每个检查点上且只能跳跃到检查点上。同时,小明可以自行再增加 m 个检查点让自己跳得更轻松。在运动会前,小明制定训练计划让自己单次跳跃的最远距离达到 L,并且学会一个爆发技能可以在运动会时使用一次,使用时可以在该次跳跃时的最远距离变为 2L。小明想知道,L 的最小值是多少可以完成这个项目?
输入格式
输入共 2 行。第一行为两个正整数 n,m。第二行为 nn个由空格分开的正整数 a1,a2,...,an。
输出格式
输出共 1 行,一个整数表示答案。
样例输入
5 3
1 3 5 16 21
样例输出
3
样例说明
增加检查点 10,13,19,因此每次跳跃距离为 2,2,5,3,3,3,2,在第三次跳跃时使用技能即可。
评测用例规模与约定
对于 20% 的评测用例,保证 n≤10^2,m≤10^3,ai≤10^3。 对于 100%的评测用例,保证 2≤n≤10^5,m≤10^8,0<ai≤10^8。
解题思路:
从原点开始起跳到第一个检查点,这段距离别忘;一次爆发可看做多给一次检查点(因为爆发能跳2L,就相当于在2L中间插个检查点,分成了两段L)。 用二分来查找最小的能满足给定m+1(+1为一次爆发)的L(即mid)。
怎么判断是否满足m+1:
①先求出在选定的mid的情况下,完成项目所需的检查点数requireM。 ②再判断所需的检查点数requireM是否满足<=m+1 ③若满足,再使right=mid-1,减小mid,看能否取更小 ④若不满足,则使left=mid+1,增大mid,使满足 ⑤直到找到最小的mid (即L)
计算完成项目所需的检查点数requireM:
通过计算每两个相邻检查点之间的距离d可以划分为多少段长度为L的段落(向上取整),即(d+mid-1)/mid(在数学中与ceil( d/mid )等价), 这两个检查点间所需的检查点数即为段落数-1即可,为(d+mid-1)/mid-1,即(d-1)/mid。
代码:
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc=new Scanner(System.in);int n=sc.nextInt();int m=sc.nextInt()+1;//爆发可以看作多给一个检查点int[] a=new int[n];for(int i=0;i<n;i++) {a[i]=sc.nextInt();}int[] distance=new int[n];distance[0]=a[0];//注意!!!从原点开始跳到第一个检查点的距离for(int i=0;i<n-1;i++) {distance[i+1]=a[i+1]-a[i];}int left=1;int right=(int)1e8;int answer=0;while(left<=right) {int mid=left+(right-left)/2;long requireM=0;for(int d:distance) {requireM+=(d-1)/mid;//d/mid的向上取整再-1,d/mid表示距离d能划分为多少段长度为mid段落,再-1即为需增加的检查点}if(requireM<=m) {answer=mid;right=mid-1;}else {left=mid+1;}}System.out.println(answer);sc.close();}}