【描述】
共N ( 1 ≤ N ≤ 100,000 )个 工作日 ,分M ( 1 ≤ M ≤ N ) 个 清算月
一个 清算月 包含一个工作日或更多连续的工作日,每一个工作日都仅被包含在一个 清算月 当中。
按顺序分组,得到一个最大值最小化的月度开支(即 在 所有可能的分组结果的最大值 中得到一个最小的)。
【输入样例】
7 5
100
400
300
100
500
101
400
【输出样例】
500
解:
#include <bits/stdc++.h>
using namespace std;
int n,m,ans,a[100005];
int judge(int mid)
{
int sum=0,cnt=1;
for(int i=1;i<=n;i++)
{
if(sum+a[i]<=mid) sum+=a[i];
/// 连加 分为一组 直到该组总和大于mid
else
{
sum=a[i]; cnt++; ///cnt记下组数 sum从a[i]开始重新连加
if(cnt>m || sum>mid) return 0;
/// 若组数超过m 或 有比mid更大的花费 返回0
}
}
return 1;
}
int main()
{
scanf("%d%d",&n,&m);
int le=0,rig=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
le=min(le,a[i]);
rig+=a[i];
}
while(le<=rig) ///不断缩小范围直到找到答案
{
int mid=(le+rig)>>1;
///取中值 mid小了就le=mid+1向右找 否则就rig=mid-1向左找
if(judge(mid)) /// 若返回1 mid>=答案
{
ans=mid; /// 先保存mid
rig=mid-1;
///若此时mid=答案 而rig=mid-1了 继续循环在judge()时只会进入else部分直到跳出循环。否则mid大了 继续缩小直到得到mid=答案。
}
else le=mid+1; /// 若返回0 则花费中有比mid更大的 mid小了
}
printf("%d\n",ans);
return 0;
}