题解 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)\),轻松通过此题。
本文来自博客园,作者:caijianhong,转载请注明原文链接:https://www.cnblogs.com/caijianhong/p/solution-p7343.html