第十二届蓝桥杯省赛 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;
}


目录
相关文章
|
1月前
|
算法 测试技术 C++
【动态规划算法】蓝桥杯填充问题(C/C++)
【动态规划算法】蓝桥杯填充问题(C/C++)
|
1月前
|
人工智能 算法 BI
第十四届蓝桥杯省赛大学C组(C/C++)三国游戏
第十四届蓝桥杯省赛大学C组(C/C++)三国游戏
|
1月前
|
人工智能 C++
第十四届蓝桥杯省赛大学B组(C/C++)整数删除
第十四届蓝桥杯省赛大学B组(C/C++)整数删除
|
1月前
|
机器学习/深度学习 算法 关系型数据库
第十五届蓝桥杯C++B组省赛
第十五届蓝桥杯C++B组省赛
82 14
|
1月前
|
算法 C++
2022年第十三届蓝桥杯大赛C/C++语言B组省赛题解
2022年第十三届蓝桥杯大赛C/C++语言B组省赛题解
37 5
|
1月前
|
算法
蓝桥杯宝藏排序 | 数据结构 | 快速排序 归并排序
蓝桥杯宝藏排序 | 数据结构 | 快速排序 归并排序
|
1月前
|
人工智能 算法
蓝桥杯真题宝藏排序详解 | 冒泡排序 选择排序 插入排序
蓝桥杯真题宝藏排序详解 | 冒泡排序 选择排序 插入排序
|
5月前
|
C++ 容器
C++之deque容器(构造、赋值、大小、插入与删除、存取、排序)
C++之deque容器(构造、赋值、大小、插入与删除、存取、排序)
|
6月前
|
算法 测试技术 C++
小唐开始刷蓝桥(八)2013年第四届C/C++ B组蓝桥杯省赛真题
小唐开始刷蓝桥(八)2013年第四届C/C++ B组蓝桥杯省赛真题
|
6月前
|
算法 C++ 数据格式
小唐开始刷蓝桥(七)2014年第五届C/C++ B组蓝桥杯省赛真题
小唐开始刷蓝桥(七)2014年第五届C/C++ B组蓝桥杯省赛真题