SDUT 2778 小明的花费预算

SDUT 2778 小明的花费预算

Time Limit: 1000MS Memory Limit: 65536KB

Problem Description


小明终于找到一份工作了,但是老板是个比较奇怪的人,他并不是按照每月每月的这样发工资,他觉得你想什么时候来取都可以,而小明恰好是一个花钱比较大手大脚的人,所以他希望每次取得钱正好够接下来的n个月的花费,以防浪费。
小明很懒,懒到他连钱都尽量不愿多带(只是嫌沉)。但是他在只有m次取钱的机会,所以他想要用m次把n个月的钱都取出来,但想要每次都尽量少取些。给你小明n个月的花费,还有可取的次数m,问小明在保证每次尽量少取些钱的情况下,最多的那次取了多少钱?当然,每次取钱只能取连续几个月的花费。

Input


多组输入。
第一行是两个整数,n(1 ≤ n ≤ 100,000)和m (1 ≤ m ≤ n)
接下来的n行是连续n个月的花费,第i+1行是第i个月的花费。

Output


输出满足最大的总花费最小的那个组的总花费。

Example Input


5 3
3
2
9
4
1

Example Output


9

Hint


将5个月分为3组,第一组(3,2),第二组(9),第三组(4,1),第二组的总花费最大为9,若按其他的方式分,花费最大的那一组的总花费将>=9.

Author


lwn

Submit(带注释版)


#include <bits/stdc++.h>

using namespace std;

int N, M;
int n[100005];
int ans;

void binsearch(int low, int high)
{
    if(low > high)//从low到high,情况越来越不理想,所以必须low <= high,当low > high的时候说明最佳答案ans已求出
        return;
    int mid, count = 1, i, sum = 0;//count代表取钱次数,sum代表每次取得钱数
    mid = (high-low) / 2 + low;//二分,设一个low和high的中值mid,代表每次允许取的最大钱数
    for(i = 0; i < N; i++)//求出若每次取得钱数不超过中值mid的条件下需要取几次
    {
        if(sum + n[i] <= mid)//再继续取1月的花费不会超过mid
            sum += n[i];//sum代表某一次取的钱数
        else
        {
            count++;//不能继续再取钱了,要再取一次
            sum = n[i];
        }
    }
    if(count > M)//需要取的次数大于允许取得次数,说明每次允许取的钱数太小了,就确定答案范围一定在mid到high之间
        binsearch(mid+1, high);
    else
    {
        ans = mid;
        binsearch(low, mid-1);//反之就减小每次允许取得钱数
    }
}

int main()
{
    int low, high;//low和high是总花费最小的那个组的总花费的范围
    while(~scanf("%d %d", &N, &M))
    {
        low = high = 0;//总花费最小的最理想情况就是,花费最大的那个月单独取1次,其他任意次取的钱数合都比这个月小,此处设low是这个最理想情况的花费。最不理想情况则是只取一次,一次取出所有的花费,此处设low是这个最不理想情况
        for(int i = 0; i < N; i++)
        {
            scanf("%d", &n[i]);
            if(n[i] > low)
                low = n[i];//最理想情况
            high += n[i];//最大花费就是只取一次全取完
        }
        binsearch(low, high);//二分的在这个范围内精确答案
        printf("%d\n", ans);
    }
    return 0;
}

Submit(纯代码版)


#include <bits/stdc++.h>

using namespace std;

int N, M;
int n[100005];
int ans;

void binsearch(int low, int high)
{
    if(low > high)
        return;
    int mid, count = 1, i, sum = 0;
    mid = (high-low) / 2 + low;
    for(i = 0; i < N; i++)
    {
        if(sum + n[i] <= mid)
            sum += n[i];
        else
        {
            count++;
            sum = n[i];
        }
    }
    if(count > M)
        binsearch(mid+1, high);
    else
    {
        ans = mid;
        binsearch(low, mid-1);
    }
}

int main()
{
    int low, high;
    while(~scanf("%d %d", &N, &M))
    {
        low = high = 0;
        for(int i = 0; i < N; i++)
        {
            scanf("%d", &n[i]);
            if(n[i] > low)
                low = n[i];
            high += n[i];
        }
        binsearch(low, high);
        printf("%d\n", ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值