数列分段 Section II

题目描述

给定一个长度为N的正整数数列 A 1 ∼ N A_{1\sim N} A1N,现要将其分成M( M ≤ N M\leq N MN)段,并要求每段连续,且每段和的最大值最小。最大值最小的定义如下:例如一个数列 4   2   4   5   1 4\ 2\ 4\ 5\ 1 4 2 4 5 1 要分成3段。将其如下分段: [ 4   2 ] [ 4   5 ] [ 1 ] [4\ 2][4\ 5][1] [4 2][4 5][1]第一段和为6,第二段和为9,第三段和为1,和的最大值为9。将其如下分段: [ 4 ] [ 2   4 ] [ 5   1 ] [4][2\ 4][5\ 1] [4][2 4][5 1]第一段和为4,第二段和为6,第三段和为6,和的最大值为6。无论如何分段,最大值不会小于6。因此,将数列 4   2   4   5   1 4\ 2\ 4\ 5\ 1 4 2 4 5 1 分成3段,每段和的最大值最小为6。## 输入格式第一行包含两个正整数N和M。第二行包含N个空格隔开的非负整数 A i A_i Ai,表示数列。## 输出格式一个正整数,即每段和的最大值最小为多少。

样例 #1

样例输入 #1

5 34 2 4 5 1

样例输出 #1

6

提示

对于20%的数据,N不超过10。对于40%的数据,N不超过1000。对于100%的数据,N不超过 1 0 5 10^5 105,M不超过N, A i A_i Ai小于 1 0 8 10^8 108,答案不超过 1 0 9 10^9 109

解题思路

这道题可以使用二分查找的思想来解决。首先,我们可以确定最大值的范围,即最大值不会小于数列中的最大值。然后,我们可以使用二分查找来确定每段和的最大值。假设我们猜测的每段和的最大值为mid,我们可以遍历数列,计算每段的和,如果和大于mid,则说明当前段的和已经超过了我们的猜测值,需要将当前段作为一段,然后继续计算下一段的和。如果我们最终得到的段数小于等于M,说明我们猜测的每段和的最大值mid是合理的,我们可以继续尝试更小的值。如果我们最终得到的段数大于M,说明我们猜测的每段和的最大值mid太小了,我们需要尝试更大的值。通过不断调整猜测值的范围,最终我们可以找到每段和的最大值的最小值。

代码实现


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

public class Main {
	static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static StreamTokenizer sr = new StreamTokenizer(in);
	static int MAXN = (int) (1e5 + 10);
	static int[] arr = new int[MAXN];
	static int n, m;

	public static void main(String[] args) throws IOException {
		n = nextInt();
		m = nextInt();
		long max = 0, min = 0;
		for (int i = 1; i <= n; i++) {
			arr[i] = nextInt();
			max += arr[i];
			min = Math.max(arr[i], min);
		}
		long mid = 0, l = min, r = max;
		while (l < r) {
			mid = l + (r - l) / 2;
			if (check(mid)) { // 大于等于m
				r = mid;
			} else {
				l = mid + 1;
			}
		}
		out.println(l);
		out.flush();
	}

	private static boolean check(long mid) {
		long sum = 0, cnt = 1;
		for (int i = 1; i <= n; i++) {
			if (sum + arr[i] > mid) {
				sum = 0;
				cnt++;
			}
			sum += arr[i];
		}
		return cnt <= m;
	}

	static int nextInt() throws IOException {
		sr.nextToken();
		return (int) sr.nval;
	}

}

以上是对题目的解题思路和代码实现的介绍。希望对你有帮助!如果有任何问题,请随时提问。

你可能感兴趣的:(二分查找与二分答案,算法,数据结构)