-
B - Sticks Problem
- POJ - 2452
- 题意:
- 给出一个数组a,求最大的j-i满足 i<j && a[i] ... a[j]中最大值为a[j],最小值为a[i]。
- 思路:
- 可以枚举左标位置i,然后二分找出满足的最远的j,只需要满足在i-j区间内最小值是a[i]即可,需要RMQ查询最小值验证。
- 原因是随着区间变大区间最小值会变小或不变。符合单调性
- 找到最大的以a[i]为最小值的区间之后,在这个区间里最大的符合题意的区间就是从 i —这段区间的最大值。
- 然后一直更新答案即可,刚开始用map 标记一下每个数的位置,由于每个数都是不同的,而且map不需要每次初始化
- 一直用即可。否则超时。也可以 再次二分区间 原因是随着区间变小区间最大值会变小或不变。符合单调性
-
#include<stdio.h> #include<map> #include<cmath> using namespace std; #define maxn 154321 map<int,int>id; int n,k,a[maxn],ans,tail; int minn[maxn][20],l; int maxx[maxn][20],r; void init() { for(int j=1; (1<<j)<=n; j++) for(int i=1; i+(1<<j)-1<=n; i++) minn[i][j]=min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]); for(int j=1; (1<<j)<=n; j++) for(int i=1; i+(1<<j)-1<=n; i++) maxx[i][j]=max(maxx[i][j-1],maxx[i+(1<<(j-1))][j-1]); } int rmqmin(int l,int r) { int k=int(log(r-l+1)/log(2.0)); int ret=min(minn[l][k],minn[r-(1<<k)+1][k]); return ret; } int rmqmax(int l,int r) { int k=int(log(r-l+1)/log(2.0)); int ret=max(maxx[l][k],maxx[r-(1<<k)+1][k]); return ret; } bool ok(int zuo,int you) { if(rmqmin(zuo,you)==a[zuo]) return true; return false; } int main() { while(scanf("%d",&n)!=EOF) { ans=-1; for(int i=1; i<=n; i++) { scanf("%d",&a[i]); id[a[i]]=i; minn[i][0]=a[i]; maxx[i][0]=a[i]; } init(); for(int i=1; i<n; i++) { tail=0; l=i+1,r=n; while(l+1<r) { int mid=(l+r)/2; if(ok(i,mid))l=mid; else r=mid; } if(ok(i,r)) tail=r; else if(ok(i,l)) tail=l; if(tail==0)continue; ans=max(ans,id[rmqmax(i,tail)]-i); } printf("%d\n",ans); } return 0; }