题意:
有n个数,问对于每一个长度为x的连续区间内最小数,最大值为多少?
x
∈
[
1
,
n
]
x \in [1,n]
x∈[1,n],输出n个数,分别代表
x
=
i
x=i
x=i时的答案。
思路:
考虑每一个数对答案的贡献。
使用单调栈,求出第
i
i
i个数向左第一个比它小的数的坐标
L
[
i
]
L[i]
L[i]和向右第一个比它小的数的坐标
R
[
i
]
R[i]
R[i],则区间最小值为
a
[
i
]
a[i]
a[i]的最大区间长度
l
e
n
len
len为:
l
e
n
=
R
[
i
]
−
L
[
i
]
−
1
len = R[i] - L[i] - 1
len=R[i]−L[i]−1
注意到如果存在长度为 l e n len len的区间包含 a [ i ] a[i] a[i],则一定存在一个区间长度为 l e n − 1 len-1 len−1的区间包含 a [ i ] a[i] a[i],故对于答案数组从右到左线性扫描,每一个数与其右边的数取一个最大值即可。
时间复杂度: O ( n ) O(n) O(n)
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int A = 1e6 + 10;
int a[A],S[A],L[A],R[A],Ans[A],tot;
int main(){
int n;
scanf("%d",&n);
for(int i=1 ;i<=n ;i++){
scanf("%d",&a[i]);
}
tot = 0;
for(int i=1 ;i<=n ;i++){
while(tot>0 && a[S[tot]]>=a[i]){
tot--;
}
if(!tot) L[i] = 0;
else L[i] = S[tot];
S[++tot] = i;
}
tot = 0;
for(int i=n ;i>=1 ;i--){
while(tot>0 && a[S[tot]]>=a[i]){
tot--;
}
if(!tot) R[i] = n+1;
else R[i] = S[tot];
S[++tot] = i;
}
for(int i=1 ;i<=n ;i++){
int len = R[i] - L[i] - 1;
Ans[len] = max(Ans[len],a[i]);
}
for(int i=n-1 ;i>=1 ;i--){
Ans[i] = max(Ans[i],Ans[i+1]);
}
for(int i=1 ;i<=n ;i++){
printf("%d%c",Ans[i],i==n?'\n':' ');
}
return 0;
}