题意:
给你一组数a[n],求满足a[i] < a[k] < a[j] (i <= k <= j)的最大的区间长度 j - i
解法1:O(n^2)
先记录每一位数A[i]后面连续大于这个数的长度len[i],然后再这个长度里[i, i+len[i] )找最大的数的下标 j,这样可求得最大的区间 j - i
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 50000+5;
using namespace std;
int n, A[maxn];
int len[maxn]; // len[i]: 大于 A[i] 的连续最大长度
int main()
{
freopen("in.txt","r",stdin);
while(scanf("%d",&n) == 1){
for(int i = 1; i <= n; ++i){
scanf("%d", &A[i]);
len[i] = 1;
}
for(int i = n; i >= 1; --i){
while(i+len[i] <= n&&A[i] < A[i+len[i]]) len[i]+= len[i+len[i]];
}
int ans = -1;
for(int i = 1; i <= n; ++i){
int r = -1, tmp = -1;
for(int j = 1; j < len[i]; ++j){
if(r < A[i+j]){
r = A[i+j];
tmp = j;
}
}
ans = max(ans, tmp);
}
printf("%d\n", ans);
}
fclose(stdin);
return 0;
}
解法2:RMQ+二分O(nlogn)
枚举i,利用二分求出a[i]右边第一个小于a[i]的数的位置k,
再求出[i, k]中最大值的位置j,若a[j] > a[i],则更新结果
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 50000+5;
using namespace std;
int n, A[maxn];
int maxval[maxn][20], minval[maxn][20];
int max1(int i, int j){
if(A[i] > A[j]) return i;
return j;
}
int min1(int i, int j){
if(A[i] < A[j]) return i;
return j;
}
void ST(){
for(int i = 1; i <= n; ++i) maxval[i][0] = minval[i][0] = i;
for(int i = 1; i <= log2(n); ++i){
for(int j = 1; j + (1<<i) - 1 <= n; ++j){
maxval[j][i] = max1(maxval[j][i-1], maxval[j + (1<<i-1)][i-1]);
minval[j][i] = min1(minval[j][i-1], minval[j + (1<<i-1)][i-1]);
}
}
}
int Query_max(int l, int r){
int k = log2(r-l+1);
return max1(maxval[l][k], maxval[r-(1<<k)+1][k]);
}
int Query_min(int l, int r){
int k = log2(r-l+1);
return min1(minval[l][k], minval[r-(1<<k)+1][k]);
}
int bsearch(int l, int r, int x){
while(l < r){
int mid = (l+r) >> 1;
if(A[Query_min(l, mid)] > A[x]) l = mid + 1;
else r = mid;
}
return l;
}
void solve(){
int ans = -1;
for(int i = 1; i <= n; ++i){
int k = bsearch(i+1, n, i);
int j = Query_max(i, k);
if(A[j] > A[i]) ans = max(ans, j - i);
}
printf("%d\n", ans);
}
int main()
{
freopen("in.txt","r",stdin);
while(scanf("%d",&n) == 1){
for(int i = 1; i <= n; ++i) scanf("%d", &A[i]);
ST();
solve();
}
fclose(stdin);
return 0;
}
解法3:单调栈O(n)
在discuss区看到大佬发的,复制下来学习。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
struct node{int low,high,id1,id2;}p,stack[50055];
int i,ans,top,x,n;
int main()
{
//freopen("in.txt", "r", stdin);
while(scanf("%d",&n) == 1)
{
top = ans = 0;
for(i = 1; i <= n; ++i)
{
scanf("%d",&x);
if(x > stack[top].high&&top)
{
while(x > stack[top].high&&top) p = stack[top--], ans = max(ans, p.id2 - p.id1);
p.high = x; p.id2 = i; stack[++top] = p;
}
else if(x < stack[top].low&&top)
{
while(x < stack[top].low) p = stack[top--], ans = max(ans, p.id2 - p.id1);
p.low = p.high = x; p.id1 = p.id2 = i; stack[++top] = p;
}
else
{
p.low = p.high = x; p.id1 = p.id2 = i;
stack[++top] = p;
}
}
while(top) p = stack[top--], ans = max(ans, p.id2 - p.id1);
printf(!ans?"-1\n":"%d\n",ans);
}
fclose(stdin);
}