题目大意:给出n个数,找出Si为最小值Sj为最大值的子序列Si...Sj,求出所有这样的子序列中j-i的最大值
输入:(可以有很多case)
n (n <= 50000)
n个数(空格分隔) (not larger than 100000)
输出:如果有这样的子序列就输出j-i,如果没有就输出-1
分析:RMQ问题。枚举区间的起始位置,二分搜索出第一个比起始位置数小的位置r,RMQ求出这个区间内最大值的位置k,如果这个最大值大于起始位置的值,就更新答案,然后循环判断完所有起始位置即可。
代码:转载自http://blog.csdn.net/hexianhao/article/details/51028370
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<cmath>
- using namespace std;
- const int maxn = 50005;
- int n,stick[maxn],dp_max[maxn][20],dp_min[maxn][20];
- int _max(int l,int r)
- {
- if(stick[l] > stick[r]) return l;
- return r;
- }
- int _min(int l,int r)
- {
- if(stick[l] < stick[r]) return l;
- return r;
- }
- void initRMQ()
- {
- for(int i = 1; i <= n; i++)
- dp_max[i][0] = dp_min[i][0] = i;
- for(int j = 1; (1 << j) <= n; j++)
- for(int i = 1; i + (1 << j) - 1 <= n; i++)
- {
- dp_max[i][j] = _max(dp_max[i][j-1],dp_max[i+(1<<j-1)][j-1]);
- dp_min[i][j] = _min(dp_min[i][j-1],dp_min[i+(1<<j-1)][j-1]);
- }
- }
- int MaxValue(int l,int r)
- {
- int k = (int)(log(double(r) - l + 1) / log(2.0));
- return _max(dp_max[l][k],dp_max[r-(1<<k)+1][k]);
- }
- int MinValue(int l,int r)
- {
- int k = (int)(log(double(r) - l + 1) / log(2.0));
- return _min(dp_min[l][k],dp_min[r-(1<<k)+1][k]);
- }
- int binsearch(int x,int l,int r)
- {
- while(l < r)
- {
- int mid = (l + r) >> 1;
- if(stick[x] < stick[MinValue(l,mid)])
- l = mid + 1;
- else r = mid;
- }
- return l;
- }
- int main()
- {
- while(scanf("%d",&n)!=EOF)
- {
- for(int i = 1; i <= n; i++)
- scanf("%d",&stick[i]);
- initRMQ();
- int ans = 0;
- for(int i = 1; i + ans < n; i++){
- int r = binsearch(i,i+1,n);
- int k = MaxValue(i,r);
- if(stick[k] > stick[i])
- ans = max(ans,k - i);
- }
- if(ans == 0) printf("-1\n");
- else printf("%d\n",ans);
- }
- return 0;
- }