倍增算法1
首先用倍增法解决一道求区间最大值问题,算是倍增的入门了。
其实也算是一种dp,不过大家把这个二维dp数组叫做ST表。
ST表数组:f[i][j],表示区间【i,i+2j-1】的最大值。这个区间的大小是2j个数。
ST表的初始化:f[i][0]=a[i]。(显然这是区间大小为1的时候)
ST表的递推过程:
1,由区间大小为1的项转移得到区间大小为21的项
2,由区间为21的项转移得到区间为22的项
3,由区间为22的项转移得到区间为23的项
。。。
这就是倍增的由来了吧。
这个递推过程的代码:
1 void RMQ(int N){ 2 for(int j=1;(1<<j)<=N;j++) 3 for(int i=1;i<=N;i++) 4 if(i+(1<<j)-1<=N) 5 f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); 6 }
经过处理后,访问一段长区间便能利用事先处理好的数据得出答案
比如询问最大值的一项处理技术:
因为区间的长度为j-i+1,所以可以取k=log2(j-i+1)。
则RMQ(A,i,j)=max(f[i][k],f[j-2^k+1][k])。
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<cmath> 6 using namespace std; 7 int a[100001],f[100001][20]; 8 9 void RMQ(int N){ 10 for(int j=1;(1<<j)<=N;j++) 11 for(int i=1;i<=N;i++) 12 if(i+(1<<j)-1<=N) 13 f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); 14 } 15 int main(){ 16 int N,M; 17 int tt; 18 cin>>tt; 19 while(tt--) 20 { 21 cin>>N; 22 for(int i=1;i<=N;i++) cin>>a[i]; 23 for(int i=1;i<=N;i++) f[i][0]=a[i]; 24 RMQ(N); 25 cin>>M; 26 while(M--){ 27 int l,r; 28 cin>>l>>r; 29 int k=(int)(log((double)(r-l+1))/log(2.0)); 30 printf("%d\n",max(f[l][k],f[r-(1<<k)+1][k])); 31 } 32 } 33 return 0; 34 }