[CF1023D] Array Restoration

Description

给你一个长度为 (n) 的数列,初始全部为 (0) ,你可以任意(任选区间)进行 (q) 次操作,第 (i) 次操作使 ([l_i,r_i]) 内的数全部变为 (i) ,你必须进行全部 (q) 次操作,且每个操作区间都不能为空,所有操作区间的并必须为 ([1,n])。现在给你一个数列,其中 (0) 代表这个位置可以是任何数,问你能否通过上述的 (q) 次操作得到这个数列。输出方案。

Solution

以下 (m) 即为题面中的 (q)

无解的判定

如果两个数之间存在比它们小的数,则无解

如果序列中不存在值为 (m) 的数,则无解

解的构造

考虑为 (0) 的位置需要怎样处理

  • 如果数列中没有 (m),则优先填 (m)

  • 如果某个位置的左侧右侧同时存在 (x),则该位置 (ge x),换言之我们在这个位置需要取它左边右边都有的数中的最大值

  • 否则填 (1)

如何维护

考虑维护一个 std::set,在某个数第一次出现时 insert(x),最后一次出现时 erase(x)

那么我们每次取 *s.rbegin() 即可

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 1000005;

int n,a[N],m,l[N],r[N];

signed main() {
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];

    for(int i=1;i<=n;i++) r[a[i]]=i;
    for(int i=n;i>=1;--i) l[a[i]]=i;

    set<int> s;
    int fg=*max_element(a+1,a+n+1)==m;
    for(int i=1;i<=n;i++) {
        if(a[i]) {
            if(i==l[a[i]]) s.insert(a[i]);
            if(i==r[a[i]]) s.erase(a[i]);
            if(s.size()>0 && a[i]<*s.rbegin()) {
                puts("NO");
                return 0;
            }
        }
        else {
            if(fg==0) {
                fg=1;
                a[i]=m;
            }
            else if(s.size()>0) {
                a[i]=*s.rbegin();
            }
            else {
                a[i]=1;
            }
        }
    }
    if(fg) {
        puts("YES");
        for(int i=1;i<=n;i++) cout<<a[i]<<" ";
    }
    else {
        puts("NO");
    }
}
原文地址:https://www.cnblogs.com/mollnn/p/12784780.html