工资(二分)

题目描述
n+e在暑假参加了打零⼯的活动,这个活动分为n个⼯作日,每个⼯作日的⼯资为Vi。有m个结算⼯钱的时间,n+e可以自由安排这些时间,也就是说什么时候拿钱,老板说的不算,n+e才有发⾔权!(因为n+e是⼟豪,他是老板的老板)
n+e不喜欢身上⼀次性有太多的钱,于是他想安排⼀下拿钱的时间,使他⼀次性拿的钱中最⼤的那次的最小。(最后⼀天⼀定要领钱)

输入
第⼀⾏2个数n,m
接下来n⾏,每⾏⼀个数,代表Vi

输出
输出⼀⾏⼀个整数,表示最小的最⼤钱数。

样例输入
7 5
100
400
300
100
500
101
400

样例输出
500

提示
100 400//300 100//500//101//400// ”//” 表示 n+e 要去拿钱。

对于20%的数据,1<=n<=20
对于另20%的数据,1≤n≤50,Vi的和不超过1000
对于100%的数据,1≤n≤100000,m≤n,Vi≤100000

思路
二分找最小的最⼤钱数,线性检验结果

代码实现

#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=100005;
const int M=4005;
const ll INF=1e14;
const ull sed=31;
const ll mod=998244353;
const double eps=1e-12;
typedef pair<int,int>P;
 
int n,m;
ll v[N],sum;
 
bool judge(ll s)
{
    int cnt=0;
    ll ret=0;
    for(int i=1;i<=n;i++)
    {
        if(ret+v[i]>s)
        {
            ret=v[i];
            cnt++;
        }
        else ret+=v[i];
        if(cnt>=m || ret>s) return false;
    }
    if(cnt<=m-1) return true;
    return false;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&v[i]);
        sum+=v[i];
    }
    ll l=0,r=sum;
    while(l<r)
    {
        ll mid=(l+r)>>1;
        if(judge(mid)) r=mid;
        else l=mid+1;
    }
    printf("%lld\n",l);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值