二分答案

0.定义

二分搜索法,是通过不断缩小解可能存在的范围,从而求得问题最优解的方法。


1.查找值

在一个有序的数组中查找一个值。
因为有序,所以可以二分。
这里就找了自己十几天前打的一个求有序序列的上界的代码。
大致是这样的:取出中间的数,如果大于要查找的值,答案就在左边,否则在右边。这样每次查找都可以把范围缩小一半。所以时间复杂度就是O(log n)了。

int LB(int A[],int n,int x)
{
    int L=0,R=n;
    while(Lint mid=(L+R)/2;
        if(A[mid]>=x) R=mid;
        else L=mid+1;
    }
    return L;
}

2.最大化最小值

顾名思义,就是通过二分答案让最小值最大。好吧我承认这是句废话
如果中间值满足题意,那么最小值大于等于中间值。否则小于中间值。

int BS()
{
    int lb=0,ub=l+1;
    while(lb+1int mid=(lb+ub)/2;
        if(check(mid)) lb=mid;
        else ub=mid;
    }
    return lb;
}

3.最小化最大值

类似上文。

int BS()
{
    int lb=0,ub=INF;
    while(lb+1int mid=(lb+ub)/2;
        if(check(mid)) ub=mid;
        else lb=mid;
    }
    return ub;
}

4.最大化平均值

给定n个物品,有自己的重量和价值。选出k个物品,使平均价值最大。
虽然有些并不一定是二分但有些也确实是二分。到时候再确定是不是二分。
这里就把用二分做的题目所用的方法推导一下好了。
定义C(x):=可以选择使得单位重量的价值不小于x。
若C(x)可行,则

ki=1v[i] ki=1w[i] x ∑ i = 1 k v [ i ]   ∑ i = 1 k w [ i ]   ≥ x

i=1kv[i] xi=1kw[i] 0 ∑ i = 1 k v [ i ]   − x ∗ ∑ i = 1 k w [ i ]   ≥ 0

i=1kv[i] i=1kxw[i] 0 ∑ i = 1 k v [ i ]   − ∑ i = 1 k x ∗ w [ i ]   ≥ 0

i=1kv[i]kw[i] 0 ∑ i = 1 k v [ i ] − k ∗ w [ i ]   ≥ 0

所以就可以用这个思路来二分答案了。

bool cmp(node p,node q) { return p.t>q.t; }
bool check(double x)
{
    for(int i=1;i<=n;i++) a[i].t=a[i].a-a[i].b*x;
    sort(a+1,a+n+1,cmp);
    double ans=0;
    for(int i=1;i<=n-k;i++) ans+=a[i].t;
    return ans>=0;
}
double BS()
{
    double lb=0.0,ub=1.0;
    while(lb+epsdouble mid=(lb+ub)/2;
        if(check(mid)) lb=mid;
        else ub=mid;
    }
    return lb;
}

5.其他的一些

  • 有可能二分的不是明显地表示上面的某个模型,这时候就要推导一发。(也有可能就不是上面的某个模型?)

  • 是不是二分要理智判断。似乎又是一句废话。问题的解一般要单调。

  • 有时候还会有一些恶心的二分套二分什么的。

你可能感兴趣的:(一些(玄学的)知识,二分)