Binary Search

非常好的博客, http://www.hawstein.com/posts/make-thiner-programming-pearls.html
教你快速读完编程珠玑

round函数 是四舍五入,靠近最近的整数

二分查找专题,瞿神推荐

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=80425#overview

题目B,对于给定数组的m划分,使得每个划分的累加和最大值最小

这里又想了一个计数问题,n个数m划分(要求连续的数划分在一起),每个至少为1,那么一共多少种。

我进入算法思维,首选dp,对于最后一个元素,所在集合有1个或多个数,因此枚举
dp(n, m)=sum(dp(n-lastsize, m-1)) lastsize=1->n-(m-1)

应该是可以算的。

然而这其实就是一个插板法,n-1块地方放m-1块板,C(n-1,m-1)

言归正传。二分可以考虑二分答案,这是常见思路。对于mid,我们尝试划分
n个数,使得每个区间sum<=mid, 看最后能不能划分m个区间,如果<=m个,说明我们的mid选大了,如果选小一点,区间数可以多一些,以达到刚好m个,但是mid还是要保留,high=mid, 否则low=mid+1.
二分下届是max(ai), 上届是sum(ai)

bool judge(LL mid)
{
    LL sum=0, cnt=0;;
    for(LL i=0;i<n;i++)
    {
        sum+=a[i];
        if(sum>mid)
        {
            cnt++;
            i--;
            sum=0;
        }
    }
    cnt++;
    return cnt<=m;
}
int main()
{
/*
#ifndef ONLINE_JUDGE
    freopen ("in.txt" , "r" , stdin);
    freopen ("out.txt" , "w" , stdout);
#endif
*/
    while(cin>>n>>m)
    {
        LL sum =0, maxx=-1;
        for(LL i=0;i<n;i++) cin>>a[i], sum+=a[i] ,maxx=max(maxx, a[i]);
        LL low=maxx, high=sum;
        while(low<high)
        {
            LL mid=(low+high)/2;
            if(judge(mid)) high=mid;
            else low=mid+1;
        }
        cout<<low<<endl;
    }
    return 0;
}

另一道更偏数值计算,感觉二分的算法很多是数值计算的内容
里面有一个性质一直没懂
题目E,是01分数规划

max(sum(aixi)/sum(bixi)) st: sum(xi)=n-k, xi=0|1

这个最大值等价于
f(L)=sum(aixi)-L*sum(bixi)

但是具体为何还不清楚。知道这个之后,就是算最大的n-k个ai-mid*bi, 然后
按照这个来二分

double epsilon=1e-7;
while(~scanf("%d%d", &n, &k))
{
    if(!n && !k) break;
    for(int i=0;i<n;i++) a[i]=getint();
    for(int i=0;i<n;i++) b[i]=getint();
    double low=0, high=1;
    while(high-low>=epsilon)
    {
        double mid=(low+high)/2;
        for(int i=0;i<n;i++) t[i]=a[i]-mid*b[i];
        sort(t, t+n);
        double f=0;
        for(int i=k;i<n;i++) f+=t[i];
        if(f>=0) low=mid;
        else high=mid;
    }
    cout<<(round)(low*100)<<endl;
}

Posted by richard爱闹 - 6月 9 2015
如需转载,请注明: 本文来自 Richard