数列分段 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;
}
标签:二分,分段,int,Section,mid,II,leq,最大值,P1182 From: https://www.cnblogs.com/ltphy-/p/18235873