一道很好的二分题

Posted emcikem

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一道很好的二分题相关的知识,希望对你有一定的参考价值。

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

#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;
}

以上是关于一道很好的二分题的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 1050 旅行(并查集)

[HNOI2006]超级英雄 网络流+二分版

二分查找,没那么简单!

一道微软面试题:“半”有序数组如何进行二分查找?

一道打印菱形的面试题

那晚征服的一道js经典的面试题