第十二届蓝桥杯省赛 C++ B组 - 双向排序

简介: 第十二届蓝桥杯省赛 C++ B组 - 双向排序

问题描述


b586f94dd7d14517b837e4eb5d9bce33.png

思路


这道题对于我这种新手小白也挺难的,看 AcWing 看了好久才弄明白,话不多说,直接上解析!

首先我们要考虑下面的几种情况:

(1)操作一(q 为 0 降序)

当出现连续的操作一时,我们只需找到其中跨越区间最大的那一个即可,因为小于它的其它区间都包含在最长的这个区间里,就不用重复的去完成降序操作了。


1f82eb6a03d14c6a831261e19633769b.png


(2)操作二(q 为 1 升序)

这个操作必须在前面进行了操作一的前提下才能进行,因为如果前面没有操作一,直接进行操作二没有意义,原本的序列就是升序的。

同样,如果出现连续的情况,要找到区间最长的那个操作。


fdc048d4753e43398a426919428a94b9.png


(3)操作一和操作二交替进行

如果操作一和操作二不是连续的,并且你当前的操作的区间要大于之前的操作一或者操作二,那么就要将当前操作的前面两个操作删除,因为当前操作会覆盖掉之前的操作。例如,当前操作一比上次操作一的区间要大,那我就将上次操作一给删除,但是两次操作二就会相邻,所以就要将操作一和操作二一同删除。

91686fc1fc884e0c951b836225672aa8.png

经过上面三种情况的排除后,我们可以发现一个规律,我的所有操作中,我的第一次操作一和操作二一定时所有操作一和操作二中包含区间最大的,因为比他小的之前的区间或相邻的区间都删除了,所以该操作之后的不相邻操作区间会不断的减小,并且是操作一和操作二交错进行的。

这样,我们只用改变相邻操作一和操作二重叠部分的次序即可,通过不断地操作,中间公共区域会变得越来越小即左边界和右边界会逐渐往中间去靠,直至左右边界相遇。

所以,我们每次操作都会改变左边界和右边界,而左边界的左边和右边界的右边就是已经排好序的部分,通过不断的缩小中间区域来逐渐填满整个列表。

ee67e47d21c44c67a14b5ceccedbe17e.png



代码

#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int, int> PII;
const int N = 100010;
PII stk[N];
int ans[N];
int m, n;
int main()
{
  scanf("%d%d", &n, &m);
  int top = 0;
  while (m--)
  {
    int p, q;
    scanf("%d%d", &p, &q);
    //如果是操作一
    if (!p)
    {
      //如果连续执行操作一,则只保留右边界值最大的那个
      while (top && stk[top].x == 0)  q = max(q, stk[top--].y);
      //如果当前的操作右边界要比上一次操作一的右边界值大,则删除前面的操作一和操作二
      while (top >= 2 && stk[top - 1].y <= q) top -= 2;
      stk[++top] = { 0,q }; //保存本次最佳的值
    }
    else if (top) //操作二之前必须要有操作一,不然没有意义
    {
      //如果连续执行操作二,则只保留左边界值最小的那个
      while (top && stk[top].x == 1)  q = min(q, stk[top--].y);
      //如果当前的操作左边界要比上一次操作二的左边界值小,则删除前面的操作一和操作二
      while (top >= 2 && stk[top - 1].y >= q) top -= 2;
      stk[++top] = { 1,q }; //保存本次最佳的值
    }
  }
  int k = n, l = 1, r = n;
  for (int i = 1; i <= top; i++)
  {
    if (stk[i].x == 0)  //如果是操作一
      while (r > stk[i].y && l <= r)  ans[r--] = k--; //右边界左移,并赋值(升序)
    else
      while (l < stk[i].y && l <= r)  ans[l++] = k--; //左边界右移,并赋值(降序)
    if (l > r)  break;
  }
  //如果 l 和 r 没有相遇即中间仍有空的区域,则需要根据最后一次操作填满
  if (top % 2 == 0) //如果最后一次操为作一,则需要将中间按降序填满
    while (l <= r)  ans[r--] = k--;
  else    //如果最后一次为操作二,则需要将中间按升序填满
    while (l <= r)  ans[l++] = k--;
  for (int i = 1; i <= n; i++)
    printf("%d ", ans[i]);
  return 0;
}


目录
相关文章
|
2天前
|
人工智能 算法 测试技术
【数学】【排序】【C++算法】3027人员站位的方案数
【数学】【排序】【C++算法】3027人员站位的方案数
|
2天前
|
测试技术
消除游戏(第十三届蓝桥杯省赛C++C组 , 第十三届蓝桥杯省赛PythonA/B/研究生组)
消除游戏(第十三届蓝桥杯省赛C++C组 , 第十三届蓝桥杯省赛PythonA/B/研究生组)
消除游戏(第十三届蓝桥杯省赛C++C组 , 第十三届蓝桥杯省赛PythonA/B/研究生组)
|
2天前
|
人工智能 BI 测试技术
三国游戏(第十四届蓝桥杯省赛C++C组)
三国游戏(第十四届蓝桥杯省赛C++C组)
|
2天前
蓝桥杯真题代码记录(数位排序
蓝桥杯真题代码记录(数位排序
9 0
|
2天前
|
测试技术 C++
[蓝桥杯 2023 省 B] 冶炼金属(c++)
[蓝桥杯 2023 省 B] 冶炼金属(c++)
27 0
|
2天前
|
算法 测试技术 C#
【模拟】【C++算法】2826. 将三个组排序
【模拟】【C++算法】2826. 将三个组排序
|
2天前
|
机器学习/深度学习 算法 调度
拓扑排序解析:计算机与数学的交汇点以及C++ 实现
拓扑排序解析:计算机与数学的交汇点以及C++ 实现
123 0
|
2天前
|
算法 搜索推荐 大数据
在C++语言中排序、查找和算法的作用
在C++语言中排序、查找和算法的作用
11 0
|
2天前
|
算法 测试技术 C++
【广度优先搜索】【拓扑排序】【C++算法】913. 猫和老鼠
【广度优先搜索】【拓扑排序】【C++算法】913. 猫和老鼠
|
2天前
|
算法 Java C语言
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-493 合并排序数组
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-493 合并排序数组
23 0