二分

lower_bound与upper_bound

整数集合上的二分


1.最佳牛围栏

原题链接

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

int cow[N];
double sum[N];
int n,m;

 

bool check(double avg)
{
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+cow[i]-avg;   //先求一下前缀和

    double minv=0;
    for(int i=0,j=m;j<=n;i++,j++)
    {
        minv=min(minv,sum[i]);
        if(sum[j]>=minv)
            return true;
    }
    return false;

    
}

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)   cin>>cow[i];
    
    double l=0,r=2000;
    
    while(r-l>1e-5)
    {
        double mid=(r+l)/2;
        if(check(mid))
            l=mid;
        else
            r=mid;
    }
    printf("%d\n",int(r*1000));
    return 0;
}

2.特殊排序

原题链接

根据数学归纳法,假设前k-1个元素已经按要求排成一行,如果能确定第k个元素应该放在哪一个前面,即可解决此问题。

可以证明二分一定可以找到一个合法的位置插入,证明如下:

  • 1.如果第k个元素比第mid个元素小。
    继续比较k与mid-1这两个元素,若第k个元素比第mid-1个元素大,则k可以插在mid-1与mid之间;否则说明元素k比元素mid-1小,那就再比较k与mid-2这两个元素,依此类推,直到发现第k个元素比第1个元素小,那就放在最前面
// Forward declaration of compare API.
// bool compare(int a, int b);
// return bool means whether a is less than b.
class Solution {
public:
    vector<int> specialSort(int N) {
        vector<int>res;
        res.push_back(1);
        for(int i=2;i<=N;i++)
        {
            int l=-1,r=res.size()-1;
            while(l<r)
            {
                int mid=(l+r+1)>>1;
                if(compare(res[mid],i))
                        l=mid;
                else
                        r=mid-1;
            }
            res.push_back(i);
            //若i小于res中的所有数,那么i要扔到0处,那么r二分后的值得是-1
            for(int j=res.size()-2;j>r;j--)swap(res[j],res[j+1]);
        }
        return res;
    }
};
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容