题目:
求某一区间的最大值。
f[a][b]中a代表的是当前的位置,b代表的是以a为起点往后移动的区间长度2^b。
1 void bz(int n) 2 { 3 for(int i=1;i<=n;i++) 4 f[i][0]=a[i];//先定义长度1为自己本身。 5 for(int j=1;(1<<j)<=n;j++)//以区间逐步移长。//tip1 6 { 7 for(int i=1;i+(1<<j)-1<=n;i++)//点的位置逐步往后移。//tip2 8 f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); 9 } 10 }
其实tip1与tip2是利用以小的区间的最大值来逐步往上推更大的区间的最值。具体怎么推呢就需要利用到倍增思想(其实跟二分很相似)。
我们来模拟一下吧!
f[1][1]=max(f[1][0],f[2][0]);f[1][2]=max(f[1][1],f[3][1]);
f[1][1]={1,2},f[1][0]={1},f[2][0]={2},f[1][2]={1,2,3,4},f[3][1]={3,4};//大括号里面代表的是位置。
因此可以看出要求f[1][1]就直接看1位置与2位置的最值,f[1][2]是由f[1][1]与f[3][1]比较得出的。在这里也体现了由小区来推广到大区间,因为所求的大区间都可以通过二进制关系分为两个小区间问题(若重叠也是没关系的),而最小的问题也就是最初定义f[a][0]为a位置本身的问题;
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cmath> 5 using namespace std; 6 const int maxn=1e3+7; 7 int num[maxn],f[1000][1000]; 8 int main() 9 { 10 int n,a,b,c,d,q,l,r; 11 while(~scanf("%d",&n)) 12 { 13 for(int i=1;i<=n;i++) 14 { 15 scanf("%d",&num[i]); 16 } 17 for(int i=1;i<=n;i++) 18 { 19 f[i][0]=num[i]; 20 } 21 for(int i=1;i<20;i++) 22 { 23 for(int j=1;j+(1<<(i-1))-1<=n;j++) 24 { 25 f[j][i]=max(f[j][i-1],f[j+(1<<(i-1))][i-1]); 26 } 27 } 28 cin>>q; 29 for(int i=1;i<=q;i++) 30 { 31 cin>>l>>r; 32 int k=(int)(log(r-l+1.0)/log(2.0)); 33 printf("%d ",max(f[l][k],f[r-(1<<k)+1][k])); 34 } 35 } 36 }