传送门
本题题意就是有一个空的盒子,给你
2
n
2n
2n个操作,每次操作要么往盒子里放一个数字,要么从盒子里拿一个最小的数字出来,保证两种操作都恰好有
n
n
n个,放入的数字为
1
∼
n
1\sim n
1∼n,并且每次放入的数字保证不相同。输入中会模拟这个操作的过程,不过只会告诉你第二种操作拿出的最小数字的值,不会告诉你第一种操作放入了什么数字。题目就是要你通过输入判断第一种操作放入了什么数字,按怎样的顺序放入的。
对于一段操作:
+
+
.
.
.
+
(
假
设
有
b
1
个
+
)
−
a
1
,
1
−
a
1
,
2
.
.
.
−
a
1
,
c
1
+
+
.
.
.
+
(
假
设
有
b
2
个
+
)
−
a
2
,
1
−
a
2
,
1
.
.
.
−
a
2
,
c
2
⋮
\begin{aligned} &+\\ &+\\ &...\\ &+(假设有b_{1}个+)\\ &- a_{1,1}\\ &- a_{1,2}\\ &...\\ &-a_{1,c_1}\\ &+\\ &+\\ &...\\ &+(假设有b_2个+)\\ &-a_{2,1}\\ &-a_{2,1}\\ &...\\ &-a_{2,c_2}\\ &\vdots\\ \end{aligned}
++...+(假设有b1个+)−a1,1−a1,2...−a1,c1++...+(假设有b2个+)−a2,1−a2,1...−a2,c2⋮
我们发现是一段
+
+
+一段
−
-
−的形式,想象将一段
−
-
−的数字
a
a
a全部堆叠在一起,就简化为如下所示:
我们其实就是想把矩形中的小格子中的数字全部放到+号中去,并且还符合题意。
我们再抽象一下,
+
+
+表示成线段的长度,矩形就不画出格子了,用矩形高度表示格子多少,知道就好,于是成为下图的情况。
上图就非常简洁了,不过只画了三个柱子,后面其实还可能有很多,就不画了。
凡事先从简单的情况入手,我们先看只有两个柱子的情况,即下面这种。
首先明白一个性质,柱子越底端的数字越小,这个很好理解,因为越底端的数字越早从盒子中拿出去,因此也越小,如果它比柱子上面的大就矛盾了。
于是柱子上的数字分布到横线上的时候,一定是柱子越底端的数字在横线上的分布离柱子越近,可以想象成柱子向左边倒下去,然后数字就刚好被分配到柱子倒下的位置。
现在我们只需要让这些柱子一个一个倒下去,看有哪些空位置就让数字分配过去就行了。
不过有个问题,到底是哪个柱子先倒为好呢?毕竟先倒的柱子对于横线上的空位有更大的选择权。对于两个柱子而言,我们发现无所谓先后顺序,假设第二个柱子倒下去的时候有一部分要跑到第一个柱子前面去,因为挤不下来了,就像下图所示:
上图用箭头表示出了柱子上各个部分的数字对应分配的区域。由于第一个柱子和第二个柱子之间空间狭小导致只能容纳
B
B
B这个部分的数字,而
A
A
A部分的数字无论怎样都得跑到第一个柱子前边去,因此不管谁先倒其实无所谓,因为在同一块区域内的话数字怎样交换顺序都是不影响结果的。
那我们增加到三个柱子看看情况又如何。
这时候情况就要复杂很多了,首先红色部分表明这是必定会“溢出”的一部分,也就是在当前柱子前的空间内容纳不下这部分,所以会被分配到前一个柱子的空间内。然后一定有
A
A
A部分内数字的最大值要小于
D
D
D部分内数字的最小值(假设最终输出答案是YES)。这个很容易想,因为
D
D
D部分会跑到第二块柱子前面去,但是它又没有在第二块柱子里,说明它的最小值都是非常大的,肯定比
A
A
A部分的最大值还大。同理有
C
<
A
C<A
C<A(简写)。不过
C
,
B
,
E
C,B,E
C,B,E部分的大小关系是未知的。
现在我们让第三个柱子先倒看看会发生什么, D D D部分自然会跑到第二个柱子前的区域去,于是第二个柱子溢出的不仅仅是 A A A部分了, B B B部分也可能溢出去一些,然后 B B B溢出去的那部分跑到第一个柱子前面了,那么是不是有可能这一部分会比 C C C的最大值更小呢?完全有可能,在这种情况下,第三个柱子倒就会导致矛盾产生。不过我们让第二个柱子倒情况就会好很多,首先 B B B不会产生溢出了,我们又早就保证 A > C A>C A>C,故 B B B倒下去后一切都还是很顺利的,然后让 A A A或 C C C倒下去(两者谁先倒无所谓了)的话会发现 D D D部分会跑到第一个柱子前面去,不过没关系,因为前面早就有关系 D > A > C D>A>C D>A>C成立,所以 D D D倒到第一个柱子前面都是不会影响结果的。
综上来看的话,只要结果是YES,那么选择让第一个柱子或第二个柱子先倒(两者谁先倒无所谓)一定能够保证产生合法的序列,当然结果为NO的话那直接输出就行了。
现在再来看四个柱子的情况:
红色部分不解释了。首先根据红色部分判断结果是YES还是NO,如果不满足
C
<
A
<
D
<
G
C<A<D<G
C<A<D<G(这里的
X
<
Y
X<Y
X<Y是指
X
X
X中的最大值小于
Y
Y
Y中的最小值)那结果一定为NO。否则结果为YES,然后跟前面一样,我们直接构造一个合法方案就行了,就让柱子从左到右挨着顺序倒。毕竟前面分析了倒后面的柱子不优(可能产生矛盾),故我们看看直接倒前面的柱子会不会保证结果合法。
于是我们发现按从左到右一个一个柱子倒的方法一定是合法的,比如说对于
G
G
G而言,满足关系
G
<
D
<
E
,
G
<
A
<
B
,
G
<
C
G<D<E,G<A<B,G<C
G<D<E,G<A<B,G<C,什么意思呢,
G
G
G放到前面任何地方其实都无所谓,不会影响到结果好坏,故这样倒下去产生的序列是合法的。
这其实是一种构造的思想,也许还可以通过倒的方式产生合法的序列,但是这种倒的方式肯定是正确无疑的。
具体实现的时候没必要这么麻烦的去判断那些溢出部分的大小关系,直接先构造,然后再模拟一下看是否合法即可。
具体代码如下:
int op[maxn*2];
int st[maxn*2],top=0,ans[maxn];
priority_queue<int,vector<int>,greater<int> >q;
int main(){
int n=rd(),cnt=0;bool failed=false;
char ch[5];
FOR(i,1,2*n+1){
rds(ch);
if(ch[0]=='-'){
int u=rd();
op[i]=u;
if(!top){
failed=true;
continue;
}
ans[st[top--]]=u;
}else{
st[++top]=++cnt;
}
}
if(failed)return wrsn("NO"),0;
int tot=0;
FOR(i,1,2*n+1){
if(!op[i]){
q.push(ans[++tot]);
}else{
if(q.top()!=op[i])return wrsn("NO"),0;
q.pop();
}
}
wrsn("YES");
FOR(i,1,n+1)wr(ans[i]),putchar(' ');
wrsn("");
}