题解: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;
}
posted @ 2026-08-10 20:00  yushihan  阅读(11)  评论(0)    收藏  举报