Date:2019/10/13
Degree of difficulty:Universal
Original Question: T103468 礼物 (普及-)
一道经典的最大值最小问题,但我还是因为左边界写错而爆零
边界
最少借的钱是数组中最大的那个数
因为如果比最大的数小的话,那么至少会有一个礼物需要向两个人借钱才可以买到,那么就失去了二分的意义(直接求平均差不多
**所以左边界是最大的数
右边界是所有数的和,**这时候只需要向1个人借钱
个人AC代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;//最大值最小
int n,m,a[100005],iro,mn;
int jud(int x){
int cnt =1;int tot =0;
for(int i = 1; i <= n; i ++){
if(tot+a[i] > x){
cnt ++; tot =a[i];
}
else if(tot <= x){
tot += a[i];
}
}
return cnt;
}
int main (){
// freopen("wage.in","r",stdin);
// freopen("wage.out","w",stdout);
scanf("%d %d",&n,&m);
m+=1;
for(int i = 1; i <=n; i++){
scanf("%d ",&a[i]);
iro+= a[i];
mn = max(mn,a[i]);
}
int l = mn;int r = iro;//借款数量
while(l < r){
int mid = (l+r)/2;
if(jud(mid) > m) l = mid + 1;
else if(jud(mid) <= m) r = mid;
}
printf("%d",r);
return 0;
}
老师标准答案
//最大值最小的模板题
#include<bits/stdc++.h>
using namespace std;
int n, m, a[100005];
int chk(int k){
int cnt = 1, sm = 0;
for(int i = 1; i <= n; i++){
if(sm + a[i] > k){
cnt++;
sm = a[i];
}
else{
sm += a[i];
}
}
return cnt;
}
int main(){
freopen("wage.in","r",stdin);
freopen("wage.out","w",stdout);
int sum = 0, mx = 0;
scanf("%d%d",&n,&m);
m++;
for(int i = 1; i <= n; i++){
scanf("%d",&a[i]);
sum += a[i];
mx = max(mx, a[i]);
}
int l = mx, r = sum, mid;
while(l < r){
mid = (l + r)/2;
int p = chk(mid);
if(p > m) l = mid + 1;
else if(p <= m) r = mid;
}
int ans = r;
printf("%d\n",ans);
return 0;
}