蓝桥杯2021年第十二届省赛真题-双向排序 - C语言网 (dotcpp.com)
题解参考:
根据题意,0是降序,1是升序;
显而易见的是,
1.当上一步操作是【0,a】,这一步操作是【0,b】,且 时,相当于b没操作,当时,相当于a的操作被覆盖掉了。两个 0降序 操作,只执行 更大的数 的操作。
例如:123456789这个序列,先执行【0,6】,序列变为654321789,后执行【0,4】,序列不变;先执行【0,4】,序列变为432156789,后执行【0,6】,序列变为654321789,相当于只要执行【0,6】;
2.当上一步操作是【1,a】,这一步操作是【1,b】,且 时,相当于a被覆盖,当时,相当于b被覆盖。两个 1升序 操作,只执行了 更小的数 的操作。
例如:987654321这个序列,先执行【1,6】,序列变为987651234,后执行【1,4】,序列变为987123456;先执行【1,4】,序列变为987123456,后执行【1,6】,序列不变;
3.如果第一个操作是【1,y】,原本就是升序,相当于没操作。所以开头遇到1操作就扔掉它。
那么,当0和1的交换操作时应该怎么办?
先不回答上面的问题,我们先看如下的这么一个情况:
Q:现在有【1,2,3,4,5,6,7,8,9】这样的序列,你遇到了如下操作命令(从上到下执行),请输出交换后得到的序列。
(0,9) |
(1,1) |
(0,7) |
(1,4) |
(0,6) |
首先观察以下这些指令,第一条指令是【0,x】,0和1的指令是交替的,以0开头的指令是排列的顺序是降序的,以1开头的指令是升序的;
之后我们一步步来执行这些指令,
操作【0,9】:987654321
操作【1,2】:912345678
操作【0,7】:965432178
操作【1,4】:965123478
操作【0,6】:965321478
最终结果是:965321478
但是在一步步执行的过程中可以看到,因为操作【0,x】中的x在变小,操作【1,y】的y在变大,所以序列中数字不断能变化的区域是在变小的(紫色的区域是已经固定的部分,黑色的区域是还可以变化的部分)
那么,为什么紫色区域是已经固定的了?
前置信息:因为肯定是0操作开头的,1操作的前面肯定是0操作,所以每次到1操作时,最左边的部分肯定已经是逆序的了。
先看左边那块紫色的已经被固定的部分,因为指令【1,y】中的y是不断变大的,所以 1操作 能把数字拉回来的 能力范围变小了,于是不在1的范围里面的数字(根据前置信息,这些数字肯定是逆序)就被留在了左边;
同理,指令【0,x】中的x不断变小,不在0的范围里面的数字(因为0操作的前面肯定是1,所以右边那部分肯定是升序)就被留在了右边;
于是回到之前的问题,
当0和1的交换操作时应该怎么办?
——把【0,x】和【1,y】的操作命令按照先来后到的顺序x递减,y递增 ,下面是当前命令是x的情况,(y的情况同理):
如果 新来的 比之前来的(这里的是x1的上方的上方,因为0和1是交替排序的) 小,那么它加入,如果新来的 比 之前来的x 大,那么新来的【0,】向上找,直到【0,】成为第一条命令,或者找到了比 还要大的,那么在【0,】的下方(这里的下方是【1,y】的位置,因为0和1是交叉排序的)的下方 插入【0,】,同时 【0,】下方的所有指令都被覆盖掉了。
例如把下面的操作排序成上面表格里的操作序列:
1 3
1 6
0 2
1 7
0 9
1 8
1 1
0 4
1 7
0 5
1 5
0 7
1 5
1 4
0 6
假设现在已经把命令全都排好了,要如何操作已经排好了的命令呢?
【0,9】:987654321
【1,2】:912345678
【0,7】:965432178
【1,4】:965123478
【0,6】:965321478
可以从这个例子中看到,如果当前是0操作,那么从右侧固定(从大到小还没有被固定的)数字,到【0,x】的x右边停下;如果当前是1操作,那么从左侧固定(从大到小还没有被固定的)数字,到【1,y】中y的左边停下;
如果操作命令都执行完了,中间的数字还没被填满,那么最后一条操作是0(降序),那么中间的数字从左往右填上从大到小的数字;最后一条操作是1(升序),那么从右往左填上从大到小的数字。