题目描述
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;
}