codeforces 911 E. Stack Sorting

探讨如何通过栈操作实现特定的全排列,使其成为非递减排列,并介绍如何构造字典序最大的可排序全排列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

Let’s suppose you have an array a, a stack s (initially empty) and an array b (also initially empty).

You may perform the following operations until both a and s are empty:

  • Take the first element of a, push it into s and remove it from a (if a is not empty);
  • Take the top element from s, append it to the end of array b and remove it from s (if s is not empty).

You can perform these operations in arbitrary order.

If there exists a way to perform the operations such that array b is sorted in non-descending order in the end, then array a is called stack-sortable.

For example, [3, 1, 2] is stack-sortable, because b will be sorted if we perform the following operations:

  1. Remove 3 from a and push it into s;
  2. Remove 1 from a and push it into s;
  3. Remove 1 from s and append it to the end of b;
  4. Remove 2 from a and push it into s;
  5. Remove 2 from s and append it to the end of b;
  6. Remove 3 from s and append it to the end of b.

After all these operations b = [1, 2, 3], so [3, 1, 2] is stack-sortable. [2, 3, 1] is not stack-sortable.

You are given k first elements of some permutation p of size n (recall that a permutation of size n is an array of size n where each integer from 1 to n occurs exactly once). You have to restore the remaining n - k elements of this permutation so it is stack-sortable. If there are multiple answers, choose the answer such that p is lexicographically maximal (an array q is lexicographically greater than an array p iff there exists some integer k such that for every i < k qi = pi, and qk > pk). You may not swap or change any of first k elements of the permutation.

Print the lexicographically maximal permutation p you can obtain.

If there exists no answer then output -1.

Input

The first line contains two integers n and k (2 ≤ n ≤ 200000, 1 ≤ k < n) — the size of a desired permutation, and the number of elements you are given, respectively.

The second line contains k integers p1, p2, …, pk (1 ≤ pi ≤ n) — the first k elements of p. These integers are pairwise distinct.

Output

If it is possible to restore a stack-sortable permutation p of size n such that the first k elements of p are equal to elements given in the input, print lexicographically maximal such permutation.

Otherwise print -1.

Examples

Input
5 3
3 2 1
Output
3 2 1 5 4

Input
5 3
2 3 1
Output
-1

Input
5 1
3
Output
3 2 1 5 4

Input
5 2
3 4
Output
-1


题意:给出某个1~n的排列的一部分,在末尾添上剩余部分,使它成为一个全排列并且满足可栈排序。如果可行,输出字典序最高的答案;如果不行输出-1。
分析:首先需要明白栈排序的原理:一个乱序的全排列a变为顺序的全排列b的过程只有两步:取出a的首部,如果是b期望的下一个数就放入b;或者不能放入b的数暂时入栈。而一旦入栈的数字就只能倒序出栈并且直接进入b,所以出栈的数必须是递增的(因为b是从小到大安放的)。
总结:如果一个全排列是可栈排序的,那么这是一个很强的条件,它必须保证进栈的数必须比栈顶的数小,如果从a取出的数既不能放入b,也不能入栈,那么就一定不是可栈排序的,反正则一定是可栈排序的,因为如果满足上述条件,b期望的下一个数是a和栈的所有数中最小的数,比它更大的数已经全部入栈了,它一定在a的首部,或者在栈的顶端。
思路:先按照要求处理给出的部分,遇到“既不能放入b,也不能入栈”的情况直接判定结果是不行。处理结束后,b期望的下一个数只可能是a的首部,栈顶,或者需要我们来添加。这里就需要判断,如果a的首部和栈顶都不是,是否能添加一个——如果之前出现过了说明期望的数被压在了栈中,是不可行的;如果没有出现过,直接添加就行了。

#include<stdio.h>
//#include<iostream>
//using std::cin;
//using std::cout;
//#include<algorithm>
//using std::sort;
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define mabs(x) ((x)>0?(x):(0-(x)))
#define N_max 200005
int n,m;
int next=1;//b期望的下一个数
int top=0;//栈顶的索引
int stack[N_max];//栈
int done[N_max] = { 0 };//记录哪些数出现过(当前在a,b或栈中)
int ipt[N_max];//输入的数列
void push(int x) {
    stack[++top] = x;
}
int pop() {
    if (top > 0) return stack[top--] ;
    else return -1;
}
int main() {
    scanf("%d %d", &n,&m);
    for (int i = 0; i < m; ++i) { 
        scanf("%d", &ipt[i]);
        //如果比栈顶小或栈为空就直接入栈
        if (ipt[i] < stack[top] || top == 0)
            push(ipt[i]);
        else {
            //处理给定部分时,不允许有不能入栈的情况出现
            printf("-1");
            return 0;
        }
        done[ipt[i]] = 1; 
        //把可以进入b的从栈顶取出
        while (stack[top] == next) { next++; pop(); }
    }

    //处理添加部分
    while (top > 0) {
        if (next != stack[top]) {
            //不能出栈,必须从没用过的数中添加一个到b
            if (done[stack[top] - 1] == 0&&m<=n) {
                //新添加的数直接记入ipt数组,并更新ipt数组的个数
                ipt[m++] = stack[top] - 1;
                //更新done数组
                done[stack[top] - 1] = 1;
                //将添加的部分入栈
                push(stack[top] - 1);
            }
            else {
            //既不能出栈,也没有合适的数添加
                printf("-1");
                return 0;
            }
        }
        //能出栈就出栈
        else { pop(); next++; }
    }
    //栈排空以后,直接按从大到小的顺序,把没用过的数添加到ipt
    int next = n;//next记录下一次检索开始的位置,把复杂度降低到O(n)
    for (int i = m; i < n; ++i) {
        for (int t = next; t >= 1; --t) {//找一个最大的没用过的数
            if (done[t] == 0) {
                ipt[i] = t; //加入ipt
                done[t] = 1; //更新done标记
                next = t;//更新next 
                break;
            }
        }
    }
    //输出
    for (int i = 0; i < n; ++i) {
        printf("%d%c", ipt[i],i==n-1?'\n':' ');
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值