【每日水题】【Comet OJ 模拟赛 Day2】收拾房间reorder

题目描述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) (1mn105) ,表示一共有 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 n10
对于 50 % 50\% 50% 的数据, n ≤ 1 0 4 n\le 10^4 n104
对于 100 % 100\% 100% 的数据, n ≤ 1 0 5 n\le 10^5 n105


输出描述

输出 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;
}

  1. 链接 ↩︎

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值