#148. 花费(二分查找)

【题目描述】:

农民约翰是一个惊人的会计,他意识到可能没有钱来经营农场。他已经准确计算出接下来的N 天,每天所要花费的钱ai。

约翰想将这N 天,划分成M 段,每段至少1天,第i段的和为sum[i]。

请你求出如何划分使得max{sum[i]}最小,其值是多少?

【输入描述】:

第一行两个整数N和M。

第二行N个整数,顺序表示每一天的花费。

【输出描述】:

输出划分M 段后,最大段的最小值。

【样例输入】:

7 5
200 300 300 200 500 221 420

【样例输出】:

500

【时间限制、数据范围及描述】:

时间:1s 空间:128M

1<=ai<=10,000; 1<=N<=100,000


详解看代码:

#include<stdio.h>
#include<iostream>

using namespace std;
const int N = 100005;
int n, m, l = 0, r = 0, mid = 0;
int a[N];

int read()

{
    int f = 1, ans = 0;
    char c;
    c = getchar();
    while(c < '0' || c > '9')
    {
        if(c == '-')
        {
            f = -1;
        }
        c = getchar();
    }
    while('0' <= c && c <= '9')
    {
        ans = ans * 10 + c - '0';
        c = getchar();
    }
    return ans * f;
}

bool IF(int mi)
{
    int sum = 0, t = 0;

    for(int i = 1; i <= n; i++)
    {
        if(sum + a[i] > mi)////如果前几个月加上这个月的钱大于这次尝试的月开销,那么说明这个月的钱应该放在下个月里 

        {
            sum = a[i];
            ++t;
        }
        else
            sum += a[i];
    }

    if(t >= m)
        return true;
    else
        return false;
}
 //如果按照mid的分割方法,最大分割出t个月大于m,则可以继续增加开销,
// 注意,这里是说,最少分出的月份是t,那么t>=m,则可以继续增加开销,以便使t变小 //本段注释为引用他人的话
//详见https://blog.csdn.net/abc15766228491/article/details/78827946

int main()
{
    freopen("51.in", "r", stdin);
    freopen("51.out", "w", stdout);
    n=read();
    m=read();
    for(int i = 1; i <= n; i++)
    {
        a[i]=read();
        l = max(a[i], l);
        r = r + a[i];
    }

    while(l <= r)
    {
        mid = (l + r) / 2;

        if(IF(mid))
            l = mid + 1;
        else
            r = mid - 1;

        mid = (l + r) / 2;
    }
    printf("%d", l);//一定是l而不是mid,因为l需要被最后一次修改才是正解,此时mid与l不是一个数,我调试了好久......
    return 0;
}
至于为什么做这题,,一方面是为了学习二分,,,,另一方面,,为了明天考试(要不然我才不那么勤奋呢^_^)................老天保佑我吧!!!嗷嗷!!
天下无双!(个人中二病)

猜你喜欢

转载自blog.csdn.net/Doc_wu/article/details/81006391