前提:必须要用BufferedReader才能AC!
*这道题为二分的模板题,不懂的可先做一下 木材加工 *
poj 2774 木材加工
Description
木材厂有一些原木,现在想把这些木头切割成一些长度相同的小段木头,需要得到的小段的数目是给定了。当然,我们希望得到的小段越长越好,你的任务是计算能够得到的小段木头的最大长度。
木头长度的单位是厘米。原木的长度都是正整数,我们要求切割得到的小段木头的长度也要求是正整数。
Input
第一行是两个正整数N和K(1 ≤ N ≤ 10000, 1 ≤ K ≤ 10000),N是原木的数目,K是需要得到的小段的数目。
接下来的N行,每行有一个1到10000之间的正整数,表示一根原木的长度。
Output
输出能够切割得到的小段的最大长度。如果连1厘米长的小段都切不出来,输出”0”。
礼物的AC代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.util.zip.CheckedInputStream;
public class Main {
static long[] sum = new long[1000010];
static int[] arr = new int[1000010];
public static void main(String[] args) throws IOException {
BufferedReader sc = new BufferedReader(new InputStreamReader(System.in));
// N,S
String[] ss = null;
String mm = sc.readLine();
ss = mm.split(" ");
int N = Integer.parseInt(ss[0]);
long S = Long.parseLong(ss[1]);
//一排石子
String[] pp = null;
String qq = sc.readLine();
pp = qq.split(" ");
//获取前缀和
for(int i = 1;i<=N;i++){
arr[i] = Integer.parseInt(pp[i-1]);
sum[i] = sum[i-1] + arr[i];
}
//二分
int l = 1,r = N;
while(l < r){
int mid = (l+r+1) >> 1;
if(check(mid,N,S)){
l = mid;
}else{
r = mid-1;
}
}
//答案是2*l
System.out.println(2*l);
}
public static boolean check(int mid,int N,long S){
//为什么有for? 其实你找到的mid只是k(2*k个石子的一半),
//也就是带走石子数量的一半,你要在一排石子中选出一段(长度为2*k)
//并拿出前k和后k个石子看看满不满足<=S,若有某一段满足,
//就代表该k可取,那就再经过二分扩大一下k,看看还满不满足,
//经过几轮操作后,目标就锁定在最右侧,即得到最优答案
for(int i = mid;i<=N-mid;i++){
if(sum[i]-sum[i-mid] <= S && sum[i+mid]-sum[i] <= S){
return true;
}
}
return false;
}
}
二分模板
check函数就是按题意的限制条件
//尽量往左找目标
while (l < r)
{
int mid = (l+r) / 2;
if (check(mid)) r = mid;
else l = mid + 1;
}
//在往右找目标
while (l < r)
{
int mid = (l + r + 1) / 2;
if (check(mid)) l = mid;
else r = mid - 1;
}