题解 LGP7343【[DSOI 2021] 电子跃迁】

posted on 2021-02-07 18:12:18 | under 题解 | source

题意简述

给出一长为 \(n\) 的数列 \(a\) 和一长为 \(m\) 的数列 \(b\),你可以交换 \((a_i,a_{i+1})\) 的位置,但不能交换 \((a_{b_i},a_{b_i+1})\) 的位置,你需要在满足限制条件的同时让数列尽量有序。\(1\leq n,m\leq 5\times 10^5\)

题目分析

补充一点题目中没说的:不能交换 \((a_{b_i},a_{b_i+1})\) 的位置,但可以交换 \((a_{b_i-1},a_{b_i})\)\((a_{b_i+1},a_{b_i+2})\) 的位置。

这道题 \(n\) 的范围比较大,\(O(n^2)\) 的冒泡排序只能骗得 \(30\) 分,考虑使用别的方法。

首先,我们要知道,仅靠交换任意 \((a_i,a_{i+1})\) 的位置,可以使数列 \(a\) 变得有序。那么,我们参照样例 \(2\),画个图:

看看这个图,这两个X把这个数列分成了 \(3\) 部分:\((a_1,a_2)\)\((a_3,a_4)\)\((a_5,a_7)\)。实际上,我们只需要对这 \(3\) 部分分别排序就可以了,因为每个部分是独立的,它的元素不能传到另一个部分,满足题目的要求。那么我们来写代码吧:

#include <cstdio>
#include <algorithm>//使用sort
using namespace std;
int n,m,a[500010],b[500010];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=m;i++) scanf("%d",&b[i]);
    sort(b+1,b+1+m);//先把b数组排个序,防止出一些***钻的数据卡我们
    for(int i=1;i<=m;i++) sort(a+b[i-1]+1,a+b[i]+1);//分部分排序,从b[i-1]到b[i]是一个部分
  	//这里要注意一下+1,由于STL的特性,传进去的东西都要"左闭右开",所以要+1把b[i]也排进去
    sort(a+b[m]+1,a+n+1);//还有最后一个部分,也要排
    for(int i=1;i<=n;i++) printf("%d ",a[i]);
    return 0;
}

复杂度 \(O(n\log n)\),轻松通过此题。

posted @ 2022-11-09 23:48  caijianhong  阅读(34)  评论(0编辑  收藏  举报