题意:
给定一组长度为n的序列a[1],a[2]…a[n](n<=2e5,a[i]<=1e9),现在对于任意一个区间长度len(1<=len<=n),要求长度为len的连续子序列中最小值的最大值是多少,比如一个序列n=5,序列元素为2,3,6,4,1,那么当长度为2时答案就是4,即子序列{a[3],a[4]}中的最小值。
思路:
对于每个数a[ i ],求出以a[ i ]为最小值的区间左右端点L[ i ]和R[ i ],方法是做两遍单调栈,对于长度为len的区间(1<=len<=n)
ans[ len ]=max( ans[ len ] , a[ i ] )
因为我们求出的L[ i ]和R[ i ]是以a[ i ]为最小值的,所以所有长度为
len ( r - l + 1 ) 的区间直接取max就可以了
接下来有个问题:有可能不存在某些长度为len的区间
思路如下
首先,长度为 n 的值是一定能在上面步骤中找到的,因为上面步骤以每个数作为最小值进行操作,而所有数中一定存在一个或多个数为整个序列的最小值,从而找到的长度一定为序列总长度
其次,对于有len个数的区间(即长度为len),它的最大值ans[ len ]一定至少为ans[ len+1 ]
证明:
#include<iostream>
using namespace std;
const int maxn = 2e5+10;
int nums[maxn];
int a[maxn];
int st[maxn];
int res[maxn];
int l[maxn],r[maxn];
int main(){
int n;
cin >> n;
for( int i = 1 ; i <= n ; i++ ) cin >> a[i] ;
int tt = 0 ;
for(int i = 1 ; i <= n; i++ ){
while( tt && a[st[tt]] >= a[i] ){
tt--;
}
if( !tt ) l[i] = 1;//如果为空说明没有左边没有比他小的,说明能维护该值为最小值的左端点为 1
else l[i] = st[tt] + 1;//因为栈顶小于他才会结束循环,要保证最小值,所以下标加一
st[++tt] = i;
}
tt = 0;
for( int i = n ; i >= 1 ; i--){
while( tt && a[st[tt]] >= a[i] ) tt--;
if( !tt ) r[i] = n;//同理
else r[i] = st[tt] - 1;//同理
st[++tt] = i;
}
//根据推理证明而来
for(int i = 1 ; i <= n ; i++ ){
int len = r[i] - l[i] + 1 ;
res[len] = max(res[len] , a[i]);
}
for(int i = n-1 ; i >= 1 ; i --){
res[i] = max( res[i] , res[i+1]);
}
for(int i = 1 ; i <= n ;i ++){
cout<< res[i] << " ";
}
}