每日一题——洛谷 P1873 砍树 (二分查找模板)

大家好,我是爬行系,今天打卡的题用到了二分查找法,就顺便复习下二分模板吧

文章目录

  • 二分查找法
    • 1.题目的特征
    • 2.二分模板
  • 例题
    • 题目描述
    • AC代码
    • 练习题


二分查找法

二分查找也就是折半查找。折半查找是将 N 个元素分成大致相同的两部分。选取中间元素与查找的的元素比较,或者与查找条件相比较,找到或者说找到下一次查找的半区。每次都将范围缩小至1/2,所以时间复杂度是 O(log2n),但是二分查找的前提是有序的,一般是从小到排列。

1.题目的特征

  • 答案具有单调性;
  • 二分答案的问题往往有固定的问法,比如:令最大值最小(最小值最大),求满足条件的最大(小)值等。

2.二分模板

// 在单调递增序列a中查找>=x的数中最小的一个(即x或x的后继)
while (low < high) {
  int mid = (low + high) / 2;
  if (a[mid] >= x)
      high= mid; 
  else 
      low = mid + 1;
}
// 在单调递增序列a中查找<=x的数中最大的一个(即x或x的前驱)
while (low < high) {
  int mid = (low + high + 1) / 2;//加一是避免出现死循环
  if (a[mid] <= x) 
      low = mid;
  else 
      high = mid - 1;
}

例题

题目描述

伐木工人 Mirko 需要砍 MM 米长的木材。对 Mirko 来说这是很简单的工作,因为他有一个漂亮的新伐木机,可以如野火一般砍伐森林。不过,Mirko 只被允许砍伐一排树。
Mirko 的伐木机工作流程如下:Mirko 设置一个高度参数 HH(米),伐木机升起一个巨大的锯片到高度 HH,并锯掉所有树比 HH 高的部分(当然,树木不高于 HH 米的部分保持不变)。Mirko 就得到树木被锯下的部分。例如,如果一排树的高度分别为 20,15,1020,15,10 和 1717,Mirko 把锯片升到 1515 米的高度,切割后树木剩下的高度将是 15,15,1015,15,10 和 1515,而 Mirko 将从第 11 棵树得到 55 米,从第 44 棵树得到 22 米,共得到 77 米木材。
Mirko 非常关注生态保护,所以他不会砍掉过多的木材。这也是他尽可能高地设定伐木机锯片的原因。请帮助 Mirko 找到伐木机锯片的最大的整数高度 HH,使得他能得到的木材至少为 MM 米。换句话说,如果再升高 11 米,他将得不到 MM 米木材。
输入格式
第 11 行 22 个整数 NN 和 MM,NN 表示树木的数量,MM 表示需要的木材总长度。
第 22 行 NN 个整数表示每棵树的高度。
输出格式
11 个整数,表示锯片的最高高度。
题目链接

AC代码

import java.io.*;
public class Main {
	static long N,M;
	static long[] tree;
	//快速输入
	static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
	static StreamTokenizer st=new StreamTokenizer(br);
	public static void main(String[] args) throws IOException {
		 N=nextLong();
		 M=nextLong();
		 tree=new long[1000010];
		 long maxlen=0;
		 for(int i=0;i<N;i++){
			 tree[i]=nextLong();
			 if(tree[i]>maxlen){
				 maxlen=tree[i];//树中最高的高度
			 }
		 }
		 long low=0,high=maxlen;
		 while(low<high){
			 long mid=(low+high+1)/2;
			 if(check(mid)){
				 low=mid;
			 }else{
				 high=mid-1;
			 }
		 }
		 System.out.println(low);
	}
	public static boolean check(long mid){
		 long sum=0;
		 for(int i=0;i<N;i++){
			 if(tree[i]>mid){
				 sum+=tree[i]-mid;
			 }
		 }
		 if(sum>=M){//说明该锯片高度太低了,意味着锯片高度再mid的右边,故low=mid;
			 return true;
		 }else{
			 return false;
		 }
	}
	public static long nextLong() throws IOException{
		st.nextToken();
		return (long)st.nval;
	}
}

练习题

分巧克力

你可能感兴趣的:(每日一题,java,数据结构,算法)