zoukankan      html  css  js  c++  java
  • RMQ区间最值

    前言

    区间最值问题就是一类求一段区间的最大值或者最小值的问题(好像是废话。。。),有时候区间很大,

    比如[1~100000000],这样的长度,暴力是肯定不行的,所以这个时候就必须用更高效的算法来解决问题。

    高级写法有两种解决方法:

    一种是ST表,另一种是线段树。

    这里只给出ST算法的形式,适合于静态区间,如果要求动态区间,那就老老实实线段树。

    ST表

    此算法是基于dp思想的一种解法

    定义

    dp( i,j )表示从第i位到第i+2j-1位这个2j长度的区间的最大值

    预处理

    dp( i, 0 )表示区间[ i, i ],所以初始化为a[i],表示区间[ i, j ]的最大值为a[ i ]

    递推式

    将长度为2j的区间分为两段长度为2j-1的区间,也就是[i,i+2j-1-1]和[i+2j-1,i+2j-1]两个区间,然后选取两个区间的最值。

    dp( i,j )=max(dp( i, j-1 ),dp( i+2j-1, j-1 )

    注意:上式圆括号后面都是 j-1,是因为i+2j-1+2j-1-1 = i+2j-1    ! ! !

    建立代码

     1 //创建RMQ 
     2 void RMQ(int n){
     3     init(n);//初始化dp[i,0]
     4     //使用了左移符号 
     5     for(int j=1;(1<<j)<=n;j++){
     6         for(int i=1;i+(1<<j)-1<=n;i++){
     7             dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
     8         }
     9     }
    10 }

    注意外部循环从j开始, 因为初始状态为dp[i][0], 以 i 为外层会有一些状态遍历不到。

    查询过程

     

    如上图,一个区间为[ l, r ],长度为 r-l+1,将其转化为2k这种形式

    也就是k=log2(r-l+1),那么就可以把原区间分成两个部分[l,l+2k-1-1][l+2k-1,r]

    dp( l, r )=dp(l,k-1),dp(l+2k-1,k-1)

    然而,由于log是向下取整,所以2k可能小于r-l-1,所以要用"两边夹"的方法来实现区间分离,如上图

    则分开的区间为[l,i+2k-1][r-2k+1,r],并不需要担心重复,毕竟是求最值

    也就是:

    dp( l, r )=max(dp( l, k ),dp(r-2k+1,k))

    最终代码

     1 #include<iostream>
     2 #include<cmath>
     3 using namespace std;
     4 const int maxn=200;
     5 int dp[maxn][maxn];
     6 //快速写入 
     7 inline int read(){
     8     int w=0,f=1;
     9     char ch=getchar();
    10     while(ch<'0'||ch>'9'){
    11         if(ch=='-') f=-1;
    12         ch=getchar();
    13     }
    14     while(ch>='0'&&ch<='9'){
    15         w=(w<<3)+(w<<1)+ch-48;
    16         ch=getchar();
    17     }
    18     return w*f;
    19 }  
    20 //初始化 
    21 inline void init(int n){
    22     for(int i=1;i<=n;i++){
    23         dp[i][0]=read();
    24     }
    25 }
    26 //创建RMQ 
    27 void RMQ(int n){
    28     init(n);
    29     //使用了左移符号 
    30     for(int j=1;(1<<j)<=n;j++){
    31         for(int i=1;i+(1<<j)-1<=n;i++){
    32             dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
    33         }
    34     }
    35 }
    36 int main(){
    37     int n=read();
    38     RMQ(n);
    39     int l=read();
    40     int r=read();
    41     //查询 
    42     int k=log2(r-l+1);
    43     printf("%d",max(dp[l][k],dp[r-(1<<k)+1][k]));
    44     return 0;
    45 } 
  • 相关阅读:
    2019.6.1 模拟赛——[ 费用流 ][ 数位DP ][ 计算几何 ]
    LOJ 2721 「NOI2018」屠龙勇士——扩展中国剩余定理
    AGC033 D~F——[ 值放到角标的DP ][ 思路+DP ][ 思路 ]
    LOJ 2719 「NOI2018」冒泡排序——模型转化
    LOJ 3094 「BJOI2019」删数——角标偏移的线段树
    CF 717A Festival Organization——斯特林数+递推求通项+扩域
    LOJ 3090 「BJOI2019」勘破神机——斯特林数+递推式求通项+扩域
    洛谷 4723 【模板】线性递推——常系数线性齐次递推
    bzoj 3924 幻想乡战略游戏 —— 动态点分治
    计算几何整理
  • 原文地址:https://www.cnblogs.com/lastonepersonwhohavebitenbycompanies/p/11011967.html
Copyright © 2011-2022 走看看