学习笔记——简单倍增算法—st算法

关于简单倍增算法

  • 倍增的解释
  • st算法

倍增的解释

关于倍增算法,顾名思义,就是成倍增长,来跳过一些可以省略的计算,达到加速的效果。

st算法

说到倍增,就不得不提st算法,这大概是倍增最典型的一个应用了。
st算法,适用于RMQ问题(区间最大值),也就是求出一个序列中,数值最大的一项。朴素做法自然是一遍扫描找最大值,但是当题目询问次数很多的时候,就很有可能超时,因此用倍增算法来进行一个优化。

以下是st算法求解RMQ问题的实现:

首先,我们用f[i][j]来表示在序列a中,第i位数字以后数2j个数之中的最大值,那么就可以得到f[i][0]=a[i]。

接下来进行一个DP的过程:

for(int j = 1;j <= ( log2(n) ); j++)
	for(int i = 1;i <= n - (1 << j) + 1; i++)
		f[i][j] = max(f[i][j-1],f[i+(1<<(j-1))][j-1]);

f[i][j]表示的区间为[i,i+2j]中的最大值,而2j=2*2j-1=2j-1+2j-1,因此,我们可以把区间[i,i+2j]分成[i,i+2j-1]和[i+2j-1+1,2j]。既然已经可以把区间划分成两份,那么DP的思路便很明了了,f[i][j]的值便可以求出来。

但是,问题所询问的区间并不一定恰好是2的幂次方,有可能会超出区间。

所以,设l为区间长度,在查询时我们可以求出一个k=log2(l),向下取整。

那么就有:l/2<=2k<=l

max(f[i][k],f[i+2j-2k][k])便是所求区间的最大值。

第一次写博客,写不好还请见谅,晚上也有点困了,上代码吧。

Luogu P3865

#include
#include
#include

using namespace std;

long f[100001][40];
int n,m;

int main(){
    cin>>n>>m;
    
    int temp;
    for(int i=1;i<=n;i++){
        scanf("%d",&temp);
        
        f[i][0]=temp;
    }
    for(int k=1;k<=(int)log2(n);k++){
        for(int i=1;i<=n-(1<<k)+1;i++){
            f[i][k]=max(f[i][k-1],f[i+(1<<(k-1))][k-1]);
        }
    }
    int l,r;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&l,&r);
        
        int k=log2(r-l+1);
        
        printf("%d\n",max(f[l][k],f[r-(1<<k)+1][k]));
    }
    return 0;
}

你可能感兴趣的:(倍增,笔记)