构造+有序集合,CF 1023D - Array Restoration

一、题目

1、题目描述

2、输入输出

2.1输入
2.2输出

3、原题链接

1023D - Array Restoration


二、解题报告

1、思路分析

先考虑合法性检查:

对于数字x,其最左位置和最右位置 之间如果存在数字比x小,则非法

由于q次操作,第q次操作是最后一次操作,所以数组中应该有q,即没q非法

这个合法性检查是很简单的,我们可以线段树,树状数组,分块,set......

考虑如何构造?

对于每个0,如果处于若干个数字的区间内,那么我们应该填的数字不能比这些区间中最大那个小

同时如果数组没有q,我们优先填q

算法流程:

预处理数组最大值ma,每个数字最左下标L\[\],最右下标R\[\]

遍历数组,用一个有序集合st来维护当前遇到的区间左端点

遇到0:

如果ma < q,那么我们填q,ma = q

否则,如果st非空,填st中最大那个

否则,填1

非0:

如果i == La\[i],ai 入st

如果 i == Ri, ai 出st

如果ai < min(st),非法输出NO

2、复杂度

时间复杂度: O(NlogN)空间复杂度:O(N)

3、代码详解

复制代码
 ​
cpp 复制代码
#include <bits/stdc++.h>
#define sc scanf
using i64 = long long;
using i128 = __int128;
using PII = std::pair<int, int>;
constexpr int inf32 = 1e9 + 7;
constexpr i64 inf64 = 1e18 + 7;
constexpr int P = 998244353;
constexpr double eps = 1e-6;

// #define DEBUG

void solve()
{
    int n, q;
    std::cin >> n >> q;
    std::vector<int> a(n), L(q + 1, -1), R(q + 1, -1);
    int ma = -1, mi = inf32;

    for (int i = 0; i < n; ++ i) {
        std::cin >> a[i], ma = std::max(ma, a[i]), mi = std::min(mi, a[i]);
        if (L[a[i]] == -1) L[a[i]] = i;
        R[a[i]] = i;
    }

    std::set<int> st;
    for (int i = 0; i < n; ++ i) {
        if (!a[i]) {
            if (ma < q)
                a[i] = q, ma = q;
            else if(st.size())
                a[i] = *std::prev(st.end());
            else
                a[i] = 1;
        }
        else {
            if (L[a[i]] == i && i < R[a[i]]) st.insert(a[i]);
            if (R[a[i]] == i && L[a[i]] < i) st.erase(a[i]);
            if (st.size() && a[i] < *std::prev(st.end())) {
                std::cout << "NO\n";
                return;
            }    
        }
    }
    if (ma < q) {
        std::cout << "NO\n";
        return;    
    }
    std::cout << "YES\n";
    for (int x : a)
        std::cout << x << ' ';

}

int main()
{
#ifdef DEBUG
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    std::ios::sync_with_stdio(false), std::cin.tie(nullptr), std::cout.tie(nullptr);
    int _ = 1;
    // std::cin >> _;
    while (_--)
        solve();
    return 0;
}
相关推荐
半个落月10 小时前
从递归到快速排序:用 JavaScript 把分治思想讲明白
javascript·算法·面试
小月土星11 小时前
JavaScript 快速排序:从 pivot、双指针到分治思想
javascript·算法·面试
小月土星11 小时前
JavaScript 递归入门:从 1 到 n 求和,再到数组扁平化
javascript·算法·面试
To_OC1 天前
LC 1 两数之和:面试第一道必考题,暴力解法直接被面试官 pass
javascript·算法·leetcode
鱼鱼不愚与1 天前
《原来如此 | 第01期:为什么导航软件能预测红绿灯倒计时?》
算法
复杂网络1 天前
论最小 Agent 计算机的形态
算法
kisshyshy2 天前
🍦 雪糕、食堂、火车厢:三幅漫画吃透栈、队列与链表
javascript·算法
猿人谷2 天前
不只是 CPU 阈值:STAR 如何用 GAT + Transformer 做容器级自动扩缩容?
人工智能·算法
复杂网络2 天前
Stable Diffusion 视觉大模型微调技术深度调研
算法