题意描述
给定n天的花销,把花销分成连续的m份,使得每一段时间花销和的最大值最小。
样例输入
7 5
100
400
300
100
500
101
400
样例输出
500
思路
设每天花销为expense[i] (0<=i<n),每段时间花销为cost[j] (0 <= j < m)
答案有一个区间:max(expense[i])<=answer<=max(cost[i])
设为[l,r]
在这个区间进行二分确定中值mid,然后看这样分组能不能恰好分出m份。如果分出m份多,说明mid太小了,舍去前半段。在后半段继续二分。反之舍去后半段在前半段二分,直到l = r,此时的mid就是答案了。需要注意的是,满足分成m份的mid可能有多个,因在恰好等于m份时缩小边界的方向是向mid更小的方向才正确,举例,当mid = 5时m = 3,当mid = 3时 m = 3,因为mid缩小的范围是向l,使得能得出正确答案answer = 3而非5。
代码
#include <bits/stdc++.h>
using namespace std;
int expense[100010];//数组存每日开销
int main(){
int n,m,l = 0,r = 0;//l和r分别为二分查找的左右界 l为单日最大值 r为总值
scanf("%d %d",&n,&m);
for(int i = 0;i < n;i++){
scanf("%d",&expense[i]);
if(expense[i] > l)l = expense[i];
r += expense[i];
}
int mid;//二分变量
do{
mid = (l+r)/2;
int x = 0,now = 0;//x代表有多少组,now代表当前组开销
for(int i = 0;i < n;i++){
if(now + expense[i] > mid)
x++,now = expense[i];
else
now += expense[i];
}
x++;//最后的一组没有超过mid不通过上面增加x,在这里单独加上。
if(x > m)l = mid+1;//大于所给的天数
else r = mid-1;
}while(l <= r);
printf("%d\n",mid);
return 0;
}