题目描述1
小 L L L 的书架上摆放着很多书。当小 L L L 想看某本书时,便会从书架抽出这本书,但看完以后往往会随手扔到桌面上。
只有当书桌上放的书足够多时,小 L L L 才会想起来把书桌上的书放回书架。 已知小 L L L 书架上原有 n n n 本书排成一排,每本书都有一个不重复的编号(编号范围 1 1 1 至 n n n )。
当小 L L L 把书桌上的书放回书架时,小 L L L 总是采用逐一插入的方式,也即保持书架上的书的顺序不变,在书架上选择一个位置(书架上第一本书前,或者相邻两本书之间,或者最后一本书后),然后往里面插入一本书;接着再选择一个位置,再插入另一本书,以此类推。
当把所有书都插入后, n n n 本书的编号会形成一个排列,小 L L L 希望知道字典序最小的排列是多少。
输入描述
输入数据包含两个整数, n n n 和 m m m ( 1 ≤ m ≤ n ≤ 1 0 5 ) (1\le m\le n\le 10^5) (1≤m≤n≤105) ,表示一共有 n n n 本书以及小 L L L 在插入第一本书前,书架上还剩 m m m 本书。
接下来 m m m 行,每行包含一个整数,表示小 L L L 在插入第一本书前,书架上还剩下的 m m m 本书的编号依次是多少。
对于
30
%
30\%
30% 的数据,
n
≤
10
n\le 10
n≤10
对于
50
%
50\%
50% 的数据,
n
≤
1
0
4
n\le 10^4
n≤104
对于
100
%
100\%
100% 的数据,
n
≤
1
0
5
n\le 10^5
n≤105
输出描述
输出 n n n 行,表示字典序最小的排列方案中 n n n 本书的编号依次是多少。
样例输入1
5 3
1
4
2
样例输出1
1
3
4
2
5
?解析?
我们要让字典序最小,显然编号从 1 1 1 开始枚举,只要找到能插的地方就插,这样的答案显然满足题意。
具体点说,我们可以维护一个栈(如果你不知道什么是栈,请点击这里),然后倒着入栈(因为出栈要从头开始出),然后我们开始从小到大枚举编号,每次和栈顶比较,如果比栈顶小,直接输出;否则将栈一直弹出直到栈顶大于它为止,然后不要忘记将它入栈,这样我们就完美的得到了一个字典序最小的方案。
当然,你会发现循环完后栈内的元素没有全部出来,于是我们可以增加一个编号为 N + 1 N+1 N+1 的书让所有元素全部出栈。(“哇~太妙了!”,蒟蒻于是说道)
因为每个元素最多入栈一次、出栈一次,所以 期望时间复杂度为: Θ ( N ) \Theta(N) Θ(N) 。
代码展示
#include<bits/stdc++.h>
#define ll long long
#define ud using namespace std
ud; const int maxn=1e5+100;
int N,M,a[maxn],Stack[maxn],top=0,flag[maxn]={};
inline long long read()
{
long long s=0,f=1; char ch;
for(;ch<'0' || ch>'9';ch=getchar()) if(ch=='-') f=-1;
for(;ch>='0' && ch<='9';ch=getchar()) s=(s<<1)+(s<<3)+ch-'0';
return s*f;
}
int main()
{
N=read(),M=read();
for(int i=1;i<=M;++i) a[i]=read(),flag[a[i]]=1;
for(int i=M;i>=1;--i) Stack[++top]=a[i];
for(int i=1;i<=N+1;++i)
{
if(flag[i]) continue;
if(Stack[top]>i) printf("%d\n",i);// 如果栈顶大于 i ,直接输出
else
{
while(Stack[top]&&Stack[top]<i)// 出栈,直到栈顶大于 i
{
int ans=Stack[top--];
printf("%d\n",ans);
}
Stack[++top]=i;
}
}
return 0;
}