CF-548-D-Mike and Feet

20 篇文章 0 订阅
7 篇文章 0 订阅

题意

给定一组长度为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] << " ";
  }
  
}
​
​

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值