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");
}
}