当前位置: 首页 > article >正文

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

数列分段 Section II

题目描述

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

关于最大值最小:

例如一数列 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 N10

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

对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 1 0 5 1\leq N\leq 10^5 1N105 M ≤ N M\leq N MN 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]中所有数的和。

函数partition用于进行二分查找。在partition函数中,首先定义了变量l和r,分别表示当前二分查找的左边界和右边界,初始时l为0,r为数组a的所有元素之和。然后调用check函数判断中间值mid是否满足条件,如果满足,则继续在[mid+1, r]范围内进行二分查找,否则在[l, mid-1]范围内进行二分查找。最后输出结果r+1,即为最终的答案。

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


AC代码

#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 = 1;
	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;
}

void partition(int l, int r) {
	if (l > r) {
		cout << r + 1 << endl;
		return;
	}
	int mid = (l + r) >> 1;
	if (check(mid)) {
		// 偏小
		partition(mid + 1, r);
	} else {
		// 偏大
		partition(l, mid - 1);
	}
}

int main() {
	int l, r;
	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];
	}
	partition(l, r);
	return 0;
}

http://www.kler.cn/a/134196.html

相关文章:

  • 设计模式练习(一) 单例模式
  • 今日 AI 简报 | 开源 RAG 文本分块库、AI代理自动化软件开发框架、多模态统一生成框架、在线图像背景移除等
  • Leecode热题100-35.搜索插入位置
  • 如何从头开始构建神经网络?(附教程)
  • 【算法】——二分查找合集
  • 第74期 | GPTSecurity周报
  • 【论文解读】GPT Understands, Too
  • 阿里云ECS11月销量王 99元/年
  • <b><strong>,<i><em>标签的区别
  • 什么是美国服务器,有哪些优势,适用于什么场景?
  • 分库分表
  • 提高视频性能的 5 种方法
  • Ubuntu 20.04 LTS ffmpeg gif mp4 互转 许编译安装ffmpeg ;解决gif转mp4转换后无法播放问题
  • 【Java】ExcelWriter自适应宽度工具类(支持中文)
  • 5 redis的GEO操作
  • 2023/11/19总结
  • 【Flink 问题集】The generic type parameters of ‘Collector‘ are missing
  • linux gdb调试
  • 【数据结构】图的简介(图的逻辑结构)
  • 【ATTCK】MITRE Caldera-emu插件
  • Windows网络「SSL错误问题」及解决方案
  • Python中的迭代器、生成器和装饰器
  • 蓝桥杯单片机综合练习——工厂灯光控制
  • 2311rust到31版本更新
  • 莹莹API管理系统源码附带两套模板
  • 二元分类模型评估方法