题目大意:
题目描述
对于给定的一个长度为N的正整数数列 A_{1\sim N}A 1∼N,现要将其分成 M(M\leq NM≤N)段,并要求每段连续,且每段和的最大值最小。
关于最大值最小:
例如一数列 4\ 2\ 4\ 5\ 1 要分成 33 段。
将其如下分段:
[4\ 2][4\ 5][1]
[4 2][4 5][1]
第一段和为 66,第 22 段和为 99,第 33 段和为 11,和最大值为 99。
将其如下分段:
[4][2\ 4][5\ 1]
[4][2 4][5 1]
第一段和为 4,第 2 段和为 6,第 3 段和为 6,和最大值为 6。
并且无论如何分段,最大值不会小于 66。
所以可以得到要将数列 4\ 2\ 4\ 5\ 1要分成 3 段,每段和的最大值最小为 6。
输入格式
第 1 行包含两个正整数 N,M。
第 2行包含 N 个空格隔开的非负整数 A_iA
i,含义如题目所述。
输出格式
一个正整数,即每段和最大值最小为多少。
样例
输入 #1
5 3
4 2 4 5 1
输出 #1
6
说明/提示
对于 20%20% 的数据,N\leq 10N≤10。
对于 40%40% 的数据,N\leq 1000N≤1000。
对于 100%100% 的数据,1\leq N\leq 10^51≤N≤10 5,M\leq NM≤N,A_i < 10^8A i<108,答案不超过 10^910 9 。
解题思路:
左端点设为数列中最大的数,右端点设为数列的和,对其进行二分
以每次二分出的数mid作为每段和来判断数列可以分为多少段,假设为K段
若K>m,说明分的段数过多,应将mid变大,则使左端点=mid+1
若K<=m,尝试更小的mid, 令右端点=mid-1
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,x,f[100001],p,l,r,mid,sum,ans,maxn;
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>x;
f[i]=f[i-1]+x,maxn=max(maxn,x);
}
l=maxn;
r=f[n];
while(l<=r){
mid=(l+r)>>1;
p=1,sum=1;
for(int i=2;i<=n;i++){
if(f[i]-f[p-1]>mid)
p=i,sum++;
}
if(sum>m){
l=mid+1;
}else{
r=mid-1;
ans=mid;
}
}
cout<<ans;
return 0;
}