Openjudge 1.11 06:月度开销

06:月度开销

总时间限制: 

1000ms

内存限制: 

65536kB

描述

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

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

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

输入

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

输出

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

样例输入

7 5

100

400

300

100

500

101

400

样例输出

500

提示

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

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
int n, m, a[100009], maxx = 0, tot, ans;
bool check(int);


int main()
{
    scanf("%d%d", &n, &m);                /* 输入n天,m个财政周期 */
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        tot += a[i];                    /* 二分的右端点是总的开销 */
        if (a[i] > maxx)
            maxx = a[i];            /* 二分的左端点是n天中最大的开销 */
    }
    int l = maxx, r = tot, mid;
    while (l <= r)                        /* 二分查找 */
    {
        mid = (l + r) >> 1;
        if (check(mid))             /* 如果中间值可以 */
        {
            ans = mid;          /* 记录答案 */
            r = mid - 1;      /* 缩小范围 */
        }
        else
            l = mid + 1;            /* 否则扩大范围 */
    }
    printf("%d", ans);                    /* 输出最小值 */
}


bool check(int x)                             /* 当最小值是x时是否可以 */
{
    int sum = 0, yfen = 1;
    for (int i = 1; i <= n; i++)
    {
        if (sum + a[i] > x)           /* sum是一直累加,当超过x时月份++,说明这一天自己另一个月份 */
        {
            sum = a[i];
            yfen++;
        }
        else
            sum += a[i];
    }
    if (yfen <= m)
        return(1);  /* 月份等于m时正好分成m个月份,小于m时,可以将某些月份中的天数拆开组成新月份,满足分成m个月份 */
    else
        return(0);
}

猜你喜欢

转载自blog.csdn.net/qq_51491918/article/details/124381495