一道很好的二分题

最大化最小值,二分找出一个数,是的所有的数都满足大于这个数,那这个数就是最小值,然后二分找到这个数字的最大值即可
二分可以最大化最小值,最小化最大值
传送门

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#define ll long long
const int maxn = 5e4+500;
const int inf = 0x3f3f3f3f;
const double eps = 1e-5;
using namespace std;
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return f*x;
}
ll a[maxn];
int n,d;
int day[maxn];
bool check(ll x){//每天都需要达到这么多的开心值
    ll sum=0;//每天的开心值
    int k=0;
    for(int i=1;i<=d;i++){
        while(sum<x){
            k++;
            sum+=a[k];
            if(k>n)return 0;//巧克力不够吃了
        }
        sum/=2;
    }
    return 1;
}
void getans(ll x){//每天吃的值
    ll sum=0;
    int k=0;
    for(int i=1;i<=d;i++){
        while(sum<x){
            k++;
            sum+=a[k];
            day[k]=i;
        }
        sum/=2;
    }
}
int main(){
    cin>>n>>d;
    ll l=0,r=0;
    for(int i=1;i<=n;i++)a[i]=read(),r+=a[i];
    ll mid=0;
    ll ans=0;
    while(l<=r){
        mid=(l+r)/2;
        if(check(mid)){//找到一个最小值,每天都吃后的值都≥这个值
            l=mid+1;
            ans=mid;
        }else r=mid-1;
    }
    printf("%lld\n",ans);
    getans(ans);
    for(ll i=1;i<=n;i++){
        if(day[i])printf("%d\n",day[i]);
        else printf("%d\n",d);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Emcikem/p/11806971.html