分析:(http://www.cnblogs.com/rainydays/archive/2012/07/10/2584576.html)先对整个数组分别构造最大值RMQ和最小值RMQ的数组。然后,枚举子段起点,对于每个起点求出这个起点是区间最小值的最远终点(用二分查找)。然后在这个区间内找到最大值位置,从起点到最大值位置这个区间就是起点所对应的符合题意的最大区间。枚举过所有的起点之后,结果就求出来了。其中二分还是比较灵活。如果不用hash的话,那么rmq的时候保存下标而不是值即可。
discuss里有人说单调栈甚至暴搜也能AC。
#include <stdio.h> #include <string.h> #include <math.h> #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define N 50005 int dmax[N][20],dmin[N][20],s[N],hash[100005]; int n; void st(){ int i,j; int k = log((double)n+1)/log(2.0); for(i = 1;i<=n;i++) dmax[i][0] = dmin[i][0] = s[i]; for(j = 1;j<=k;j++) for(i = 1;i+(1<<j)-1<=n;i++) dmax[i][j] = max(dmax[i][j-1], dmax[i+(1<<(j-1))][j-1]), dmin[i][j] = min(dmin[i][j-1], dmin[i+(1<<(j-1))][j-1]); } int querymin(int a,int b){ int k = log((double)(b-a+1))/log(2.0); return min(dmin[a][k], dmin[b-(1<<k)+1][k]); } int querymax(int a,int b){ int k = log((double)(b-a+1))/log(2.0); return max(dmax[a][k], dmax[b-(1<<k)+1][k]); } int search(int x,int low,int high){ int j,mid; int base = low-1; while(low <= high){ mid = (low+high)>>1; j = querymin(base,mid); if(j < x) high = mid-1; else low = mid+1; } return high; } int main(){ while(scanf("%d",&n) != EOF){ int i,j,end,res=0; memset(hash,0,sizeof(hash)); for(i = 1;i<=n;i++){ scanf("%d",&s[i]); hash[s[i]] = i;//由于这些数各不相同,所以可以用hash } st(); for(i = 1;i<n;i++){ end = search(s[i],i+1,n);//这个二分还是比较灵活的 j = hash[querymax(i,end)]-i; res = max(res,j); } printf("%d\n",(!res)?-1:res); } return 0; }
不用hash,rmq保存下标:
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define N 50005 #define M 100005 int s[N],n,dmin[N][20],dmax[N][20]; void st(int n){ int i,j,k = log((double)n)/log(2.); for(i = 1;i<=n;i++) dmin[i][0] = dmax[i][0] = i; for(j = 1;j<=k;j++) for(i = 1;i+(1<<j)-1<=n;i++){ if(s[dmin[i][j-1]] < s[dmin[i+(1<<(j-1))][j-1]]) dmin[i][j] = dmin[i][j-1]; else dmin[i][j] = dmin[i+(1<<(j-1))][j-1]; if(s[dmax[i][j-1]] > s[dmax[i+(1<<(j-1))][j-1]]) dmax[i][j] = dmax[i][j-1]; else dmax[i][j] = dmax[i+(1<<(j-1))][j-1]; } } int qmax(int a,int b){ int k = log((double)(b-a+1))/log(2.); if(s[dmax[a][k]] < s[dmax[b-(1<<k)+1][k]]) return dmax[b-(1<<k)+1][k]; return dmax[a][k]; } int qmin(int a,int b){ int k = log((double)(b-a+1))/log(2.); if(s[dmin[a][k]] > s[dmin[b-(1<<k)+1][k]]) return dmin[b-(1<<k)+1][k]; return dmin[a][k]; } int search(int b,int low,int high){ int mid; while(low <= high){ mid = (low+high)>>1; if(s[qmin(low,mid)] < b) high = mid-1; else low = mid+1; } return high; } int main(){ while(scanf("%d",&n)!=EOF){ int i,j; int res = -1; for(i = 1;i<=n;i++) scanf("%d",&s[i]); st(n); for(i = 1;i<n;i++){ j = search(s[i],i+1,n); int tmp = qmax(i,j); res = max(res,tmp-i); } printf("%d\n",!res?-1:res); } return 0; }