B4171 [BCSP-X 2024 6 月小学高年级组] 选择排序 题解
免责声明:此题解是对 mcturtle的题解的分析
完整题目
B4171 [BCSP-X 2024 6 月小学高年级组] 选择排序
题目描述
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是每趟找出第 i i i 小的元素(也就是 A [ i ∼ n ] A[i \sim n] A[i∼n] 中最小的元素),然后将这个元素与数组第 i i i 个位置上的元素 A [ i ] A[i] A[i] 交换;在 n − 1 n-1 n−1 趟之后序列 A A A 变为升序。
例如 A = [ 3 , 4 , 1 , 5 , 2 ] A = [3, 4, 1, 5, 2] A=[3,4,1,5,2]:
- 第 1 趟交换 A [ 1 ] , A [ 3 ] A[1], A[3] A[1],A[3],序列变为 [ 1 , 4 , 3 , 5 , 2 ] [1, 4, 3, 5, 2] [1,4,3,5,2];
- 第 2 趟交换 A [ 2 ] , A [ 5 ] A[2], A[5] A[2],A[5],序列变为 [ 1 , 2 , 3 , 5 , 4 ] [1, 2, 3, 5, 4] [1,2,3,5,4];
- 第 3 趟交换 A [ 3 ] , A [ 3 ] A[3], A[3] A[3],A[3],序列不变;
- 第 4 趟交换 A [ 4 ] , A [ 5 ] A[4], A[5] A[4],A[5],序列变为 [ 1 , 2 , 3 , 4 , 5 ] [1, 2, 3, 4, 5] [1,2,3,4,5];
现在给定初始序列 A [ 1 ∼ n ] A[1 \sim n] A[1∼n](保证 A A A 是排列,即 1 ∼ n 1 \sim n 1∼n 每个数恰好出现一次)和 m m m 个询问 q [ 1 , 2 , … , m ] q[1, 2, \ldots, m] q[1,2,…,m](保证 q [ i ] < q [ i + 1 ] q[i] < q[i + 1] q[i]<q[i+1]),请你依次输出第 q [ i ] q[i] q[i] 趟之后的序列 A A A。输入格式
第一行 2 个整数 n , m n, m n,m。
第二行 n n n 个整数 A [ 1 ∼ n ] A[1 \sim n] A[1∼n],保证 A A A 是排列。
第三行 m m m 个整数 q [ 1 ∼ m ] q[1 \sim m] q[1∼m],保证 q [ i ] < q [ i + 1 ] q[i] < q[i + 1] q[i]<q[i+1]。输出格式
输出 m m m 行,第 i i i 行包含 n n n 个整数代表第 q [ i ] q[i] q[i] 趟之后的序列 A A A。
输入输出样例 #1
输入 #1
5 4 3 4 1 5 2 1 2 3 4输出 #1
1 4 3 5 2 1 2 3 5 4 1 2 3 5 4 1 2 3 4 5输入输出样例 #2
输入 #2
6 3 6 4 2 3 1 5 1 3 5输出 #2
1 4 2 3 6 5 1 2 3 4 6 5 1 2 3 4 5 6说明/提示
对于所有数据,满足 1 ≤ n ≤ 1 0 5 , 1 ≤ m ≤ 10 , 1 ≤ A [ i ] ≤ n , 1 > ≤ q [ i ] < q [ i + 1 ] < n 1 \leq n \leq 10^5, 1 \leq m \leq 10, 1 \leq A[i] \leq n, 1 >\leq q[i] < q[i + 1] < n 1≤n≤105,1≤m≤10,1≤A[i]≤n,1>≤q[i]<q[i+1]<n,保证 A A A 是排列。
- 对于测试点 1~8: n ≤ 10 n \leq 10 n≤10;
- 对于测试点 9~13: n ≤ 2000 n \leq 2000 n≤2000;
- 对于测试点 14~20: n ≤ 1 0 5 n \leq 10^5 n≤105;
1. 读题
- 模拟选择排序的过程。
- 时间复杂度不能为 O ( n 2 ) \operatorname{O (n^2)} O(n2)。
- 重点:保证 A A A 是排列,即 1 ~ n 1~n 1~n 每个数恰好出现一次
2. 解题思路
- 由于直接模拟选择排序会导致超时所以我们需要一种新思路这是错误示例。
- 用数组
t
t
t 标记每一个需要交换的值,如
t[a[i]]=i也可以理解为相对于 a a a 数组,数组与下标反着使用。 - 每次交换 a a a 数组 t t t 数组都需要换。
3. 代码片段分析
- 数据的定义、准备与输入:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,m,a[N],m1,t[N];
//n :被排序数字的个数。
//m :查询次数。
//m1 :当前查询。
//t :标记数组。
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++){
scanf("%d",&a[i]);
t[a[i]]=i;//边输入边标记。
}
- 选择排序模拟部分与输出:
int m2=1;//从上一次的查询位置开始遍历。
while(m--)// m 次查询。
{
int m1;
cin>>m1;//边读入边计算
for(int i=m2;i<=m1;i++){//从上一次的查询位置开始遍历。
int t1=t[i],t2=a[i];//由于 a[i]、 t[i] 的值会不断变化,需要先记录。
swap(a[i], a[t[i]]);
t[i]=i;
t[t2]=t1;
}
for (int i=1;i<=n;i++)
cout<<a[i]<<" ";
m2=m1;//查询位置需要更新。
cout<<endl;//千万别忘了换行。
}
4. AC代码
由于此题解是对 mcturtle 的题解的分析,就不出示 AC 代码了。
如果对你有帮助,点个赞再走吧!谢谢!
1198

被折叠的 条评论
为什么被折叠?



