3780. 构造数组 (单调栈)

Posted CCSU_Cola

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了3780. 构造数组 (单调栈)相关的知识,希望对你有一定的参考价值。

题目链接

题意:

给定一个长度为 n 的整数数组 m1,m2,…,mn。

现在,请你构造一个数组 a1,a2,…,an。

对于构造的数组,有以下三点要求:

  1. ∀i∈[1,n],1≤ai≤mi 成立。
  2. ∀i∈[1,n], 不存在数对 j,k,i 同时满足 j<i<k 且 aj>ai<ak。
  3. 数组中所有元素之和尽可能大。

请输出任意合理方案。

思路:

由题知道,形成的数组一定是只有一个峰的,也就是说只需要选定其中一个点为最大值,两边非递增就可以了,于是可以先用单调栈分别维护某个值为峰时的前缀和与后缀和,找到以最大值时的峰在哪,就可以按照非递增的思路得到数组了。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll a[500010];
ll L[500010],R[500010];
int st[510000];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    int top=0;
    for(int i=1;i<=n;i++){
        while(top&&a[st[top]]>=a[i]){
            top--;
        }
        L[i]=L[st[top]]+(ll)(i-st[top])*a[i];
        st[++top]=i;
    }
    top=0;
    st[0]=n+1;
    for(int i=n;i>=1;i--){
        while(top&&a[st[top]]>=a[i]){
            top--;
        }
        R[i]=R[st[top]]+(ll)(st[top]-i)*a[i];
        st[++top]=i;
    }
    ll res=0;
    int k;
    for(int i=1;i<=n;i++){
        if(res<L[i]+R[i+1])res=L[i]+R[i+1],k=i;
    }
    for(int i=k-1;i>=1;i--){
        a[i]=min(a[i],a[i+1]);
    }
    for(int i=k+2;i<=n;i++){
        a[i]=min(a[i],a[i-1]);
    }
    for(int i=1;i<=n;i++){
        printf("%d ",a[i]);
    }
}

以上是关于3780. 构造数组 (单调栈)的主要内容,如果未能解决你的问题,请参考以下文章

AcWing 构造数组(单调栈)

数据结构--单调栈--构造数组的MaxTree

ACwing 3780. 构造数组

ACwing 3780. 构造数组

2021牛客多校2 - Stack(单调栈+拓扑)

poj 3415 后缀数组+单调栈