题意
给出一个长度为 n n n 的正整数序列 a a a,将其分为 m m m 段,每段和的最大值最小,求是多少?
思考
因为题目中出现了最大中的最小,所以考虑二分每段和的最大中的最小值。
若有一段就一个元素,那么最大值即为自己,所以左端点取所有元素的最大值。若整体都是一段,那最大值即为整体的和,右端点则为整个序列的和。
随后进行二分。我们枚举一遍序列中的所有变量,用一个 s u m sum sum 来记录每段的和, c n t cnt cnt 来记录具体划分的段数。如果 s u m sum sum 加上当前元素还是小于我们当前二分的每段和的最大中的最小,就将 s u m sum sum 更新。否则,就说明这一段装不下,就将 s u m sum sum 重新开始累加,再将 c n t + 1 cnt+1 cnt+1。
最后,如果我们划分的段数比题目中要求的段数 m m m 还要少的话,说明每段和的最大值中的最小值还可以更小,否则说明它太小了,必须更大一些。
代码
#include<bits/stdc++.h>
using namespace std;
int a[1000001];
int n,m,l=0x3f3f3f3f,r;
int ans;
bool check(int x)
{
int sum=0,cnt=0;
for(int i=1;i<=n;i++)
{
if(x<a[i]) return 0;
if(a[i]+sum<=x) sum+=a[i];
else sum=a[i],cnt++;
}
return cnt<m;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
l=min(l,a[i]);r+=a[i];
}
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d",ans);
return 0;
}