题目大意说:给出一系列的木棒的长度,求出一个最大的区间[x,y],满足所有的len[k]>len[i] && len[k]<len[j] ,i<=k<=j。我看的题目分类说这个题目用RMQ,所有就用了RMQ实现,由于开始的时候我是枚举的所有的区间,所以肯定超时,后来改为从i找出以i开始的最大区间范围,然后在这个范围内求出最大值的下标j,那么j就是从i开始的所有>i且<j的最大区间,枚举采用二分,这样时间复杂度为O(nlogn).
#include <iostream>#include <stdio.h>#include <cmath>const int N=50001;using namespace std;int m[N],large[N][17],smal[N][17];inline int get_max(int a,int b){ return a>b?a:b;}inline int get_min(int a,int b){ return a<b?a:b;}void initrmq(int n){ int i,j; for(i=0;i<n;i++) { large[i][0]=i; smal[i][0]=i; } for(j=1;(1<<j)<=n;j++) { for(i=0;i+(1<<j)-1 < n;i++) { if(m[large[i][j-1]] > m[large[i+(1<<(j-1))][j-1]]) large[i][j]=large[i][j-1]; else large[i][j]=large[i+(1<<(j-1))][j-1]; if(m[smal[i][j-1]] < m[smal[i+(1<<(j-1))][j-1]]) smal[i][j]=smal[i][j-1]; else smal[i][j]=smal[i+(1<<(j-1))][j-1]; } }}int querymin(int i,int j){ int k=(int)(log(1.0*(j-i+1))/log(2.0)); if(m[smal[i][k]] < m[smal[j-(1<<k)+1][k]]) return smal[i][k]; return smal[j-(1<<k)+1][k];}int querymax(int i,int j){ if(i>j) { int tmp=i; i=j; j=tmp; } int k=(int)(log(1.0*(j-i+1))/log(2.0)); if(m[large[i][k]] > m[large[j-(1<<k)+1][k]]) return large[i][k]; return large[j-(1<<k)+1][k];}//找出以i开头的最大区间范围int findIdx(int n,int l){ int mid,i=l,j=n-1; while(i+1<=j) { mid=(i+j)>>1; if(querymin(l,mid) == l)//如果现在的区间最小值下标是l,则扩大范围,否则缩小范围 i=mid+1; else j=mid-1; } return j;}int solve(int n){ int i,j,ans=0,k,l,r; l=0; r=n-1; for(i=0;i<n-1;i++) { j=findIdx(n,i); k=querymax(i,j);// cout<<j<<" "<<k<<endl; if(k-i > ans) ans=k-i; } if(ans) return ans; return -1;}int main(){ int i,n; while(scanf("%d",&n)!=EOF) { for(i=0;i<n;i++) scanf("%d",&m[i]); memset(large,0,sizeof(large)); memset(smal,0,sizeof(smal)); initrmq(n); int ans=solve(n); printf("%d\n",ans); } return 0;}
来源:https://www.cnblogs.com/buptLizer/archive/2011/09/17/2179536.html