[NOIP-P0512]收入计划

题目描述

高考结束后,同学们大都找到了一份临时工作,渴望挣得一些零用钱。从今天起,Matrix67将连续工作N天(1<=N<=100 000)。每一天末他可以领取当天及前面若干天里没有领取的工资,但他总共只有M(1<=M<=N)次领取工资的机会。Matrix67已经知道了在接下来的这N天里每一天他可以赚多少钱。为了避免自己滥用零花钱,他希望知道如何安排领取工资的时间才能使得领到工资最多的那一次工资数额最小。注意Matrix67必须恰好领工资M次,且需要将所有的工资全部领走(即最后一天末需要领一次工资)。

输入

第一行输入两个用空格隔开的正整数N和M

以下N行每行一个不超过10000正整数,依次表示每一天的薪水。

输出

输出领取到的工资的最大值最小是多少。

样例输入

7 5
100
400
300
100
500
101
400

样例输出

500

提示

采取下面的方案可以使每次领到的工资不会多于500。这个答案不能再少了。

100 400 300 100 500 101 400 每一天的薪水

<------1 <-------2 <---3 <---4 <---5 领取工资的时间

500 400 500 101 400 领取到的工资

代码

#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<iostream>
#include<cmath>
#define maxn 100010
using namespace std;
typedef long long LL;
int n,m;
int a[maxn],sum[maxn];
 
 
bool check(int mid)
{
    int i=1,cnt=0,ret=0,sum=0;
    for(int i=1;i<=n;i++)ret+=a[i];
 
    while(cnt<m && i<=n)
    {
        while(cnt<m && sum+a[i]<=mid && i<=n)
        {
            ret-=a[i];
            sum+=a[i];
            i++;
        }
        cnt++;
        sum=0;
    }
 
    if(ret>0)return 0;
    return 1;
}
 
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    scanf("%d",&a[i]);
    int A=0,B=1000000000,ans;
    for(int i=0;i<50;i++)
    {
        int mid=(A+B)/2;
        if(check(mid))
        B=mid,ans=mid;
        else
        A=mid;
    }
 
    cout<<ans<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/LJA001162/p/12538500.html