【洛谷 P1182】数列分段 Section II 题解(二分答案+循环)

数列分段 Section II

题目描述

对于给定的一个长度为N的正整数数列 A 1 ∼ N A_{1\sim N} A1∼N,现要将其分成 M M M( M ≤ N M\leq N M≤N)段,并要求每段连续,且每段和的最大值最小。

关于最大值最小:

例如一数列 4 2 4 5 1 4\ 2\ 4\ 5\ 1 4 2 4 5 1 要分成 3 3 3 段。

将其如下分段:

4 2 \] \[ 4 5 \] \[ 1 \] \[4\\ 2\]\[4\\ 5\]\[1\] \[4 2\]\[4 5\]\[1

第一段和为 6 6 6,第 2 2 2 段和为 9 9 9,第 3 3 3 段和为 1 1 1,和最大值为 9 9 9。

将其如下分段:

4 \] \[ 2 4 \] \[ 5 1 \] \[4\]\[2\\ 4\]\[5\\ 1\] \[4\]\[2 4\]\[5 1

第一段和为 4 4 4,第 2 2 2 段和为 6 6 6,第 3 3 3 段和为 6 6 6,和最大值为 6 6 6。

并且无论如何分段,最大值不会小于 6 6 6。

所以可以得到要将数列 4 2 4 5 1 4\ 2\ 4\ 5\ 1 4 2 4 5 1 要分成 3 3 3 段,每段和的最大值最小为 6 6 6。

输入格式

第 1 1 1 行包含两个正整数 N , M N,M N,M。

第 2 2 2 行包含 N N N 个空格隔开的非负整数 A i A_i Ai,含义如题目所述。

输出格式

一个正整数,即每段和最大值最小为多少。

样例 #1

样例输入 #1

复制代码
5 3
4 2 4 5 1

样例输出 #1

复制代码
6

提示

对于 20 % 20\% 20% 的数据, N ≤ 10 N\leq 10 N≤10。

对于 40 % 40\% 40% 的数据, N ≤ 1000 N\leq 1000 N≤1000。

对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 1 0 5 1\leq N\leq 10^5 1≤N≤105, M ≤ N M\leq N M≤N, A i < 1 0 8 A_i < 10^8 Ai<108, 答案不超过 1 0 9 10^9 109。


思路

函数check用来判断当前的x是否满足条件。在函数check中,会遍历数列a[N],将当前位置的数加到sum上,并判断sum是否超过x。如果超过x,则创建新区间,将sum重新赋值为当前位置的数,并将cnt加1。最后,返回cnt是否大于m。

首先读入n和m的值,然后读入数列a[N]的值,并初始化l和r的值。因为所有元素都要划入区间内,所以要保证最大的元素也要被划进某一个区间,l初始化为数列a[N]中的最大值。如果把所有元素都划进区间,那么区间的最大值肯定不会超过所有元素的和,r初始化为数列a[N]中所有数的和。

使用二分法来寻找满足条件的x。在每一次循环中,计算mid的值,并调用check函数判断是否满足条件。如果满足条件,则说明x偏小,将l更新为mid+1。如果不满足条件,则说明x偏大,将r更新为mid-1。

注意:check函数中,需要将区间数cnt初始化为1,因为最少有一个区间。


AC代码

cpp 复制代码
#include <algorithm>
#include <iostream>
#define AUTHOR "HEX9CF"
using namespace std;

const int N = 1e6 + 7;

int n, m;
int a[N];

bool check(int x) {
	int sum = 0;
	int cnt = 0;
	for (int i = 1; i <= n; i++) {
		int tmp = sum + a[i];
		if (tmp > x) {
			sum = a[i];
			cnt++;
		} else {
			sum = tmp;
		}
	}
	// cout << x << " " << cnt << endl;
	return cnt >= m;
}

int main() {
	int l, r, mid;
	l = 0;
	r = 0;
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		l = max(l, a[i]);
		r += a[i];
	}
	while (l <= r) {
		mid = (l + r) >> 1;
		if (check(mid)) {
			// 偏小
			l = mid + 1;
		} else {
			// 偏大
			r = mid - 1;
		}
	}
	cout << l << endl;
	return 0;
}
相关推荐
虾球xz1 小时前
游戏引擎学习第276天:调整身体动画
c++·学习·游戏引擎
虾球xz1 小时前
游戏引擎学习第275天:将旋转和剪切传递给渲染器
c++·学习·游戏引擎
AndrewHZ1 小时前
【图像处理基石】什么是油画感?
图像处理·人工智能·算法·图像压缩·视频处理·超分辨率·去噪算法
.格子衫.1 小时前
015枚举之滑动窗口——算法备赛
数据结构·算法
J先生x2 小时前
【IP101】图像处理进阶:从直方图均衡化到伽马变换,全面掌握图像增强技术
图像处理·人工智能·学习·算法·计算机视觉
爱coding的橙子4 小时前
每日算法刷题 Day3 5.11:leetcode数组2道题,用时1h(有点慢)
算法·leetcode
虾球xz6 小时前
游戏引擎学习第268天:合并调试链表与分组
c++·学习·链表·游戏引擎
fpcc6 小时前
跟我学c++高级篇——模板元编程之十三处理逻辑
c++
格林威7 小时前
Baumer工业相机堡盟工业相机的工业视觉中为什么偏爱“黑白相机”
开发语言·c++·人工智能·数码相机·计算机视觉
Dream it possible!8 小时前
LeetCode 热题 100_只出现一次的数字(96_136_简单_C++)(哈希表;哈希集合;排序+遍历;位运算)
c++·leetcode·位运算·哈希表·哈希集合