BLMOOC4003月度开销

总时间限制:1000ms

内存限制:65536kB

描述:农夫约翰是一个精明的会计师。他意识到自己可能没有足够的钱来维持农场的运转了。他计算出并记录下了接下来 N (1 ≤ N ≤ 100,000) 天里每天需要的开销。

约翰打算为连续的M (1 ≤ MN) 个财政周期创建预算案,他把一个财政周期命名为fajo月。每个fajo月包含一天或连续的多天,每天被恰好包含在一个fajo月里。

约翰的目标是合理安排每个fajo月包含的天数,使得开销最多的fajo月的开销尽可能少。

输入:第一行包含两个整数N,M,用单个空格隔开。
接下来N行,每行包含一个1到10000之间的整数,按顺序给出接下来N天里每天的开销。

输出:一个整数,即最大月度开销的最小值。

样例输入

7 5
100
400
300
100
500
101
400

样例输出

500

提示

若约翰将前两天作为一个月,第三、四两天作为一个月,最后三天每天作为一个月,则最大月度开销为500。其他任何分配方案都会比这个值更大。

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
bool isok(int ans);
int n,m,a[100005];
int main(){
    int i,sum=0,max=0;
    scanf("%d%d",&n,&m);
    for(i=0;i<n;i++){
        scanf("%d",&a[i]);
        if(a[i]>max)
            max=a[i];
        sum+=a[i];
    }
    int left=max;
    int right=sum;
    int ans;
    while(left<=right){
        ans=left+(right-left)/2;
        if(isok(ans))//如果可以这样分,就尝试把月度开销弄大点
            left=ans+1;
        else 
            right=ans-1;//如果不可以,就说明月度开销太大了,因该弄小点
    }
    printf("%d\n",ans);
    system("pause");
    return 0;
}
bool isok(int ans){
    int sum=0,count=0,i;
    for(i=0;i<n;i++){
        if(sum+a[i]>ans){
            count++;
            sum=a[i];
        }
        else 
            sum+=a[i];
    }
    if(count>=m)return true;
    return false;
}

 思路:二分法,初始左端点是所有月份的最大值,右端点是所有月份花销总额。在isok函数里,如果前几个月的花销总额(sum)加上当前月大于所尝试的ans,那么就把这个月放到下一个fajo月里,然后isok里的sum改成当前月的花销,重新加,同时count++,最后看看count是否大于m。

这个count指的是最少能分离出几个fajo月,如果最少分离出来的fajo月数都小于m,就说明这样分不可以。

猜你喜欢

转载自blog.csdn.net/ur_ytii/article/details/88720626