赞
踩
先考虑合法性检查:
对于数字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 == L[a[i]],a[i] 入st
如果 i == R[i], a[i] 出st
如果a[i] < min(st),非法输出NO
时间复杂度: O(NlogN)空间复杂度:O(N)
- #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;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。