OpenJ_Bailian - 4135:Monthly Expense

版权声明:本文为博主原创文章,未经博主允许不得转载。https://blog.csdn.net/uzzzhf https://blog.csdn.net/uzzzhf/article/details/89412807

Farmer John is an astounding accounting wizard and has realized he might run out of money to run the farm. He has already calculated and recorded the exact amount of money (1 ≤ moneyi ≤ 10,000) that he will need to spend each day over the next N (1 ≤ N ≤ 100,000) days.

FJ wants to create a budget for a sequential set of exactly M (1 ≤ M ≤ N) fiscal periods called "fajomonths". Each of these fajomonths contains a set of 1 or more consecutive days. Every day is contained in exactly one fajomonth.

FJ's goal is to arrange the fajomonths so as to minimize the expenses of the fajomonth with the highest spending and thus determine his monthly spending limit.

Input

Line 1: Two space-separated integers: N and M 
Lines 2..N+1: Line i+1 contains the number of dollars Farmer John spends on the ith day

Output

Line 1: The smallest possible monthly limit Farmer John can afford to live with.

Sample Input

7 5
100
400
300
100
500
101
400

Sample Output

500

Hint

If Farmer John schedules the months so that the first two days are a month, the third and fourth are a month, and the last three are their own months, he spends at most $500 in any month. Any other method of scheduling gives a larger minimum monthly limit.

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

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

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

输入
第一行包含两个整数N,M,用单个空格隔开。
接下来N行,每行包含一个1到10000之间的整数,按顺序给出接下来N天里每天的开销。
输出
一个整数,即最大月度开销的最小值。
提示
若约翰将前两天作为一个月,第三、四两天作为一个月,最后三天每天作为一个月,则最大月度开销为500。其他任何分配方案都会比这个值更大。
样例输入

7 5
100
400
300
100
500
101
400

输出
500
1

解题思路:
本题对开销用二分法进行尝试,左右区间分别是:
开销的最大值(fajo月开销至少要大于每一个月的钱)和开销的总和(如果是开销的总和,就说明fajo月就是全部的月份)

#include <iostream>
#include <cstdio>
#define MAX 100010

using namespace std;

int n, m; // n:天数 ; m:周期个数
int a[MAX];

bool judge(int mid)
{
    int sum=0,t=0;
    for(int i=0;i<n;i++)
    {
        if(sum+a[i]>mid)  //如果前几个月加上这个月的钱大于这次尝试的fajo月开销,那么说明这个月的钱应该放在下个fajo月里
        {
            sum=a[i];
            t++;  //找到一个fajo月
        }
        else sum+=a[i];  // 否则就加上这个月
    }
    //如果按照mid的分割方法,最大分割出t个月大于m,则可以继续增加开销,
    // 注意,这里是说,最少分出的月份是t,那么t>=m,则可以继续增加开销,以便使t变小
    if(t >= m)
        return true;
    else
        return false;
}

int main()
{
    int total=0, max=0;
    scanf("%d %d",&n,&m);// n:天数 ; m:周期个数
    for(int i=0 ; i<n ; i++)
    {
        scanf("%d",&a[i]);
        total += a[i];  //记录开销的总和
        if(max<a[i]) max=a[i];  //记录开销的最大值
    }
    int l=max, r=total,mid; // 二分查找的边界已确定:太机智了
    while(l <= r)
    {
        mid = l + (r-l)/2; //避免数据溢出
        if(judge(mid))
            l=mid+1; //如果可以按照要求分,就说明fajo月的开销可以变大一点
        else
            r=mid-1;  // 如果不可以,则说明fajo月开销应该变小
    }
    printf("%d\n",mid);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/uzzzhf/article/details/89412807
今日推荐