CF1023D Array Restoration 【思维+单调栈】

13 篇文章 0 订阅
7 篇文章 0 订阅

本题可利用单调栈进行求解。


解法:

  1. 忽略 0 0 0值位,在从左到右扫描数组的过程中维护单调递增栈,如遇见栈顶元素比数组值大的情况,弹出栈直至栈顶元素比数组值小,并将该值压入栈内维持单调;

  2. 同时利用集合记录已弹出元素,如遇重复值尝试再次加入单调栈,则产生非法构造

  3. 如维护单调栈过程合法,则视情况 0 0 0值位填充邻近数组值、或操作数 q q q即可(需保证区间连续且最大值 q q q出现)。

原理:

由于操作对象为连续区间,若操作合法,数组内不允许出现小值区间覆盖大值区间的情况,也就是同一大值段区间不能被其他非零小值斩断。若单调栈已弹出元素再次申请入栈,则出现了斩断情况。如图例:

在这里插入图片描述

为理解方便,读者可以将题目的操作想象为堆土过程。同一高度的高土包由于覆盖时间更晚,区间内不可能出现更低的土坑。


代码如下:

#include <iostream>
#include <stack>
#include <set>
using namespace std;
#define LL long long
 
stack<int> Sta;
set<int> hasPoped;
const int maxn = 200000 + 10;
int a[maxn];
 
int main()
{
    ios::sync_with_stdio(false);
    bool valid = true;
    bool qAppeared = false;
    bool zeroAppeared = 0;
    int n;
    int q;
    cin >> n >> q;
    int lastZeroPos;
    for (int i = 0; i < n; i ++){
        cin >> a[i];
        
        if (hasPoped.count(a[i])){
            valid = false;
        }
        if (!valid){
            continue;
        }
        
        if (a[i] == 0){
            lastZeroPos = i;
            zeroAppeared = true;
            continue;
        }
        if (a[i] == q){
            qAppeared = true;
        }
        
        while (Sta.size() && Sta.top() > a[i]){
            hasPoped.insert(Sta.top());
            Sta.pop();
        }
        Sta.push(a[i]);
    }
    if (!valid || (qAppeared == false && zeroAppeared == false)){
        cout << "NO" << endl;
        return 0;
    }
    cout << "YES" << endl;
 
    for (int i = 0; i < n; i ++){
        if (a[i] == 0){
            a[i] = (i != 0 ? a[i-1] : 1);
        }
    }
    if (!qAppeared){
        a[lastZeroPos] = q;
    }
    for (int i = 0; i < n; i ++){
        if (i)  cout << " ";
        cout << a[i];
    }
    cout << endl;
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sycamore_Ma

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值