51Nod 1437 单调栈

题目链接


题意:
有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 len1的区间包含 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值