zoukankan      html  css  js  c++  java
  • 基于DP+位运算的RMQ算法

    来源:http://blog.csdn.net/y990041769/article/details/38405063

    RMQ算法,是一个快速求区间最值的离线算法,预处理时间复杂度O(n*log(n)),查询O(1),所以是一个很快速的算法,当然这个问题用线段树同样能够解决。

    问题:给出n个数ai,让你快速查询某个区间的的最值。

    算法分类:DP+位运算

    算法分析:这个算法就是基于DP和位运算符,我们用dp【i 】【j】表示从第 i 位开始,到第 i + 2^j -1 位的最大值或者最小值。

    那么我求dp【i】【j】的时候可以把它分成两部分,第一部分从 i 到 i + 2 ^( j-1 ) - 1 ,第二部分从 i + 2 ^( j-1 )  到 i + 2^j - 1 次方,其实我们知道二进制数后一个是前一个的二倍,那么可以把 i ---  i + 2^j  这个区间 通过2^(j-1) 分成相等的两部分, 那么转移方程很容易就写出来了。

    转移方程: mm [ i ] [ j ] = max ( mm [ i ] [ j - 1 ] , mm [ i + ( 1 << ( j - 1 ) ) ] [ j - 1 ] );

    代码:

    void rmq_isit(bool ok)  
    {  
        for(int i=1;i<=n;i++)  
            mm[i][0]=mi[i][0]=a[i];  
        for(int j=1;(1<<j)<=n;j++)  
        {  
            for(int i=1;i+(1<<j)-1<=n;i++)  
            {  
                if(ok)  
                    mm[i][j]=max(mm[i][j-1],mm[i+(1<<(j-1))][j-1]);  
                else  
                    mi[i][j]=min(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);  
            }  
      
        }  
    }  

    那么查询的时候对于任意一个区间 l -- r ,我们同样可以得到区间差值 len = (r - l + 1)。

    那么我们这一用小于2^k<=len,的 k 把区间分成可以交叉的两部分l 到 l+ (1<<k) -1, 到 r -(1<<k)+1 到 r 的两部分,很easy的求解了。

    查询代码:

    int rmq(int l,int r)  
    {  
        int k=0;  
        while((1<<(k+1))<=r-l+1)  
            k++;  
        //printf("%d %d %d %d
    ",l,l+(1<<k),r-(1<<k)+1,r-(1<<k)+1+(1<<k));  
        int ans1=max(mm[l][k],mm[r-(1<<k)+1][k]);  
        int ans2=min(mi[l][k],mi[r-(1<<k)+1][k]);  
        return ans1-ans2;  
    }  

    例题: POJ Balanced Lineup

    ac代码

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int maxn =  50008;
    int a[maxn],mx[maxn][30],mn[maxn][30];
    int n,m;
    
    int main(){
        ios::sync_with_stdio(0);//c++ 关同步 ac
        cin.tie(0);
        cout.tie(0);
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            mx[i][0]=mn[i][0]=a[i];
        }   
        for(int j=1; (1<<j)<=n; j++)
        {
            for(int i=1;i+(1<<j)-1<=n;i++)
            {
                mx[i][j]=max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]);
                mn[i][j]=min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
            }
        }
        for(int i=1;i<=m;i++)
        {
            int le,ri;
            cin>>le>>ri;
            int len = ri-le+1;
            int k=0;
            while((1<<(k+1))<=len)
                k++;
            int ans1=max(mx[le][k],mx[ri-(1<<k)+1][k]);
            int ans2=min(mn[le][k],mn[ri-(1<<k)+1][k]);
            cout<<ans1-ans2<<endl;
        }
    
        return 0;
    }

     

  • 相关阅读:
    [SSRS] Use Enum values in filter expressions Dynamics 365 Finance and Operation
    Power shell deploy all SSRS report d365 FO
    display method in Dynamics 365 FO
    How To Debug Dynamics 365 Finance and Operation
    Computed columns and virtual fields in data entities Dynamics 365
    Azure DevOps for Power Platform Build Pipeline
    Create readonly entities that expose financial dimensions Dynamics 365
    Dataentity call stack dynamics 365
    Dynamics 365 FO extension
    Use singletenant servertoserver authentication PowerApps
  • 原文地址:https://www.cnblogs.com/ckxkexing/p/8497148.html
Copyright © 2011-2022 走看看