• 倍增答案


    众所周知有一种很实用的算法叫做二分答案。

    二分答案可以解决一些答案具有单调性的问题。

    比如说:洛谷 P2678 跳石头,这是再基本不过的二分答案了吧?

    答案满足单调性意为,如果让你找的答案为满足某种条件的最小值x,那么大于x的所有值也都合法,小于x的所有值都不合法。

    或者是,如果让你找的答案为满足某种条件的最大值x,那么小于x的所有值也都合法,大于x的所有值都不合法。

    合法或不合法的判定在于check函数的返回值。

    这个二分答案的算法一般是这样实现的:(以跳石头为例)

    int ans;
    int ll=0;
    int rr=maxl;
    while(ll<=rr)
    {
        int mid=(ll+rr)/2;
        if(check(mid))
        {
            ll=mid+1;
            ans=mid;
        }else
        {
            rr=mid-1;
        }
    }

    最后求出来的ans就是答案。

    可以看出,最短跳跃距离很小的时候都能被满足,所以题目要求我们求一个最大值。

    而且满足单调性:比某个值大的距离都不能被满足,小于等于某个值的距离都可以被满足。

    这就是单调性。

    因为满足单调性,所以用二分答案就行。

    但是经过长时间的应用我发现二分答案有一些小缺点:l、r的边界判断(即while循环的退出条件)很烧脑。

    又联想到倍增LCA的算法实际上也是一个类似二分答案的过程。

    比LCA浅的节点都是公共祖先,比LCA深的节点都不是公共祖先,我们要在这里找一个最近(也就是最深)公共祖先(LCA)。

    但是这里我们利用数的二进制表示来倍增,而并没有二分答案。

    所以我想到了倍增答案的算法,类似倍增LCA。

    还是以跳石头为例:

    int ans=0;
    for(int i=30;i>=0;i--)
    {
        if(check(ans|(1<<i)))ans|=(1<<i);
    }

    这样之后,ans的值就是答案。

    可以看出代码与倍增LCA很相似。

    正确性也是毋庸置疑。

    只要i这一位加上去还合法,那就加上去。

    最后肯定得到一个合法且最大的值,也就是合法的最大值。

    那么如果大的值都合法,让我们求一个合法的最小值呢?

    合法的最小值不就是不合法的最大值+1嘛。

    这样我们求出不合法的最大值就行了。

    int ans=0;
    for(int i=30;i>=0;i--)
    {
        if(!check(ans|(1<<i)))ans|=(1<<i);
    }
    ans=ans+1;

    倍增答案大法好!

    如果各位大佬发现了什么bug请在底下评论哦~

    谢谢!

  • 相关阅读:
    一个人的旅行 dij(),评测的时候有点惨
    CodeFroce Round 340 div2 E XOR and Favorite Number【莫队算法】
    [HihoCoder-1185] 连通性·三 【tarjan+缩点】
    2017百度之星初赛(A)1001,1005,1006解题报告
    HDU 5961&AOJ 821 传递
    pair
    优先队列 priority_queue
    ccf 201903-5
    memset 和 fill 的区别
    ccf 20190302
  • 原文地址:https://www.cnblogs.com/cervusy/p/9609213.html
Copyright © 2020-2023  润新知