P1182 数列分段 Section II

数列分段 Section II

题目描述

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

关于最大值最小:

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

将其如下分段:

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

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

将其如下分段:

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

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

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

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

输入格式

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

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

输出格式

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

样例 #1

样例输入 #1

5 3
4 2 4 5 1

样例输出 #1

6

提示

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

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

对于 $100%$ 的数据,$1\leq N\leq 10^5$,$M\leq N$,$A_i < 10^8$, 答案不超过 $10^9$。


算法1

(二分答案) $O(n)$

【分析】

为何用二分
从题目中 <每段和的最大值最小>中能看出这题目需要用二分来解决.

求最大值的最小。即向左逼近

1.二分什么:每区间和的最大值
2.二分边界:
选取每种情况的极限值-有两种
(1)一个数作为一个区间时的最大值
(2)整个区间和的最大值

for(int i=1;i<=n;i++){
    l = max(l, a[i]);   //一个数作为一个区间是的最大值 因此需要去整个区间中的最大值
    r += a[i];    //每个数的累加就是整个区间和的最大值
}

3.判断依据:分段数
假设我们当前二分得到的mid值作为每个区间的最大值时
根据分出来的段数和题目要求的段树来进行比较选择二分区域
(1)分出来的段数小于或等于题目要球的分段数

---说明当前的区间和的最大值太大了需要再小点 因此 r=mid;

(2)分出来的段数大于题目要求的分段数

---说明当前区间和的最大值太小了,需要再大点,因此l=mid+1;

4.需要注意的点
cnt = 1; 最小一个区间

C++ 代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m;
int a[N];
int l,r,mid;

bool check(int mid){
	int sum=0,cnt=1; //注意!!! cnt初值为 1 
	
	for(int i=1;i<=n;i++){
		
		if(sum + a[i] <= mid) sum += a[i];
		
		else {
			sum = a[i];  //a[i]作为独立的区间
			cnt++;
		}
	}
	if(cnt <= m) return 1; 
	else return 0;
}
int main(){
	cin>>n>>m;
	
	for(int i=1;i<=n;i++) cin>>a[i];
	
	for(int i=1;i<=n;i++){
	
		l=max(l,a[i]);
		
		r+=a[i];
	}
	while(l<r){
		mid=l+r>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	cout<<l;
	return 0;
} 

posted @   LTphy  阅读(50)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示