题解:CF911E Stack Sorting
首先我们要知道栈的性质是先进后出,然后我们先来模拟一下进出栈的过程。
例如,\(a\) 数组中的数分别为 \(a_{1},a_{2}...,a_{k},...a_{n}\),并且 \(a_{k}=1\),那我们可以把 \(a_{1}\) 到 \(a_{k}\) 放入栈 \(s\),这时栈顶元素是 \(a_{k}\),也就是 \(1\),我们就可以弹出 \(a_{k}\),放入 \(b\) 数组的末尾,接下来要放 \(2\) 了,不难发现,如果 \(2\) 的位置在 \(a_{k}\) 的后面,我们只需要像前面一样把 \(a_{k+1}\) 到 \(2\) 之间的元素入栈,然后弹出 \(2\) 就可以,然后就是 \(2\) 在 \(a_{k}\) 前面的情况。
我们可以分成两类,第一种是 \(a_{k-1}=2\),那么就是弹出 \(1\) 后,直接弹出 \(2\) 就可以。第二种是 \(2\) 在 \(a_{k-1}\) 之前,如果想要弹出 \(2\),就必须弹出 \(2\) 到 \(a_{k-1}\),之间的数,但是如果弹出的话,那么在 \(b\) 数组中 \(2\) 前面就会有比 \(2\) 大的数,就不合法了可以直接输出 \(-1\)。
总结一下就是:在给出的前 \(k\) 个元素中,如果 \(a_{i}\) 的左边有比 \(a_{i}\) 小的元素,并且这个元素比 \(a_{i}\) 右边的某个元素大的话,就可以直接输出 \(-1\) 了。
用不等式可以表示成:\(j<i<k\) 并且 \(a_{k}<a_{j}<a_{i}\)。
\(a_{j}\) 可以用 set 维护,并在 set 中二分小于 \(a_{i}\) 的最大的数,\(a_{k}\) 可以用后缀最小值维护。
还有一种需要输出 \(-1\) 的情况,可以参考样例 \(4\),就是构造出来的 \(a_{k}\) 后面的数,不满足上面总结的性质,具体可以看代码 \(39\) 和 \(40\) 行,我们需要找到 \(x\) 没有在前 \(k\) 个数中出现过,并且 \(x+1\) 在前 \(k\) 个数中出现过的数,在第 \(4\) 个样例中,\(2\) 没有出现过,\(3\) 出现过,我们就可以找 \(3\) 的右边有没有比 \(3\) 大的数,这里可以用单调栈维护,如果有就满足了上面总结的性质,直接输出 \(-1\) 就可以。
注意:题目中要求字典序最大。
细节可以看代码 \(44\) 到 \(46\) 行,至于为什么不把不在前 \(k\) 个数中的数直接倒着输出,而是要把每一段连续的数,按照区间数值的范围从小到大,把每一段的数从大到小倒着输出,可以看样例 \(3\) 这个反例,因为直接倒着输出的话 \(a_{k+1}\) 右边一定会有比它小的,假设这个数为 \(t\),因为 \(a_{k+1}\) 和 \(t\) 不是连续的,所以前 \(k\) 个数中一定会有数大于 \(t\),就不满足性质了。
剩下大于前 \(k\) 个数中最大值的数,直接倒着输出就可以。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int a[N],stk[N],s[N],top;
int st[N],mi[N];
set<int> se;
int main(){
int n,k,mx=0;
scanf("%d%d",&n,&k);
for(int i=1;i<=k;i++){
scanf("%d",&a[i]);
st[a[i]]=i;
mx=max(mx,a[i]);
}
mi[k+1]=0x3f3f3f3f;
for(int i=k;i>=1;i--){
mi[i]=min(mi[i+1],a[i]);
}
se.insert(a[1]);
se.insert(0);
for(int i=2;i<k;i++){
auto it=se.lower_bound(a[i]);
it--;
if(*it>mi[i+1]){
printf("-1");
return 0;
}
se.insert(a[i]);
}
for(int i=k;i>=1;i--){
while(top&&stk[top]<=a[i]) top--;
if(top==0) s[i]=0;
else s[i]=stk[top];
stk[++top]=a[i];
}
int cnt=k;
int t=1;
for(int i=1;i<=mx;i++){
if(st[i]||(!st[i]&&!st[i+1])) continue;
if(s[st[i+1]]){
printf("-1");
return 0;
}
for(int j=i;j>=t;j--){
if(!st[j]) a[++cnt]=j;
}
t=i+1;
}
for(int i=n;i>mx;i--){
if(!st[i]) a[++cnt]=i;
}
for(int i=1;i<=n;i++){
printf("%d ",a[i]);
}
return 0;
}

浙公网安备 33010602011771号