当前位置:   article > 正文

Atcoder Beginner Contest 350 C - Sort

Atcoder Beginner Contest 350 C - Sort

Atcoder Beginner Contest 350

Contest Duration: 2024-04-20(Sat) 20:00 - 2024-04-20(Sat) 21:40 (local time) (100 minutes)

C - Sort

Problem Statement

You are given a permutation A=(A 1 ​ ,…,A N ​ ) of (1,2,…,N). Transform A into (1,2,…,N) by performing the following operation between 0 and N−1 times, inclusive: Operation: Choose any pair of integers (i,j) such that 1≤i<j≤N. Swap the elements at the i-th and j-th positions of A. It can be proved that under the given constraints, it is always possible to transform A into (1,2,…,N).

翻译

给定一个排列 A=(A1, ..., AN) ,其中包含数字 1 到 N 的一个排列。通过执行 0 到 N-1 次操作,将排列 A 转换为 (1, 2, ..., N)。每次操作如下:选择任意一对整数 (i, j),其中 1≤i<j≤N,在排列 A 中交换第 i 个位置和第 j 个位置上的元素。在给定的约束条件下,可以证明始终可以将排列 A 转换为 (1, 2, ..., N)。

思路

通过从开头迭代元素并将每个元素与正确位置上的元素交换,最多可以通过 (N-1) 次操作实现目标。

如果在这个过程中每次都尝试查找元素 i 在数组 A 中的当前位置,那么在最坏情况下,每次查找都会耗费 O(N) 的时间,总共将会耗费 O(N^2) 的时间,导致超时(Time Limit Exceeded)的结果。

相反,除了数组 A 外,还要维护另一个数组 pos,用于表示值 i 在数组 A 中的位置,并相应地更新它。例如,如果 A=(3,1,2,4),则 pos=(2,3,1,4)。 这样,可以在 O(1) 的时间内引用数组 A 中元素 i 的当前位置,总共需要 O(N) 的时间来解决整个问题。

来看看C知道写的代码(可能TLE):

这个问题的目标是将给定的排列A转换为(1,2,…,N)。转换操作是选择任意一对整数(i,j),其中1≤i<j≤N,然后交换A中第i个和第j个位置上的元素。根据给定的约束条件,可以证明总是可以将A转换为(1,2,…,N)。

输入格式为:N A1 A2 … AN,其中N表示排列的长度,A1到AN表示排列中的元素。

输出格式为:K+1行,第一行包含K,表示操作的次数。接下来的K行中,每行包含一个操作所选择的i和j,用空格分隔。

以下是一个C++代码及题解的示例:

  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. int main() {
  5. int N;
  6. cin >> N;
  7. vector<int> A(N);
  8. for (int i = 0; i < N; i++) {
  9. cin >> A[i];
  10. }
  11. vector<pair<int, int>> operations;
  12. // Perform the necessary operations to transform A into (1,2,...,N)
  13. for (int i = 0; i < N; i++) {
  14. if (A[i] != i + 1) {
  15. int j = i + 1;
  16. while (A[j - 1] != i + 1) {
  17. j++;
  18. }
  19. operations.push_back(make_pair(i + 1, j));
  20. swap(A[i], A[j - 1]);
  21. }
  22. }
  23. int K = operations.size();
  24. cout << K << endl;
  25. for (int i = 0; i < K; i++) {
  26. cout << operations[i].first << " " << operations[i].second << endl;
  27. }
  28. return 0;
  29. }

另一个解法:

C - Sort
置换环,有两种写法

1.
对于错位的元素,可以将应该在该位置的元素调换过来,这种写法就需要两个数组互相映射,比较绕,不推荐写这种。

2.
对于错位的元素,可以选择将该元素替换至它应该在的地方,每次替换都至少能让一个元素归位,所以最多也是 n − 1 n-1n−1 次就可以有序。写起来更方便,只需要一个数组维护此时各个元素的位置,然后每次while当前元素错位,交换即可,代码:

  1. #include <bits/stdc++.h>
  2. // #define int long long
  3. #define inf 0x3f3f3f3f
  4. #define ll long long
  5. #define pii pair<int, int>
  6. #define db double
  7. using namespace std;
  8. const int maxn = 2e5 + 10;
  9. const int mod = 998244353;
  10. int arr[maxn], pos[maxn];
  11. signed main() {
  12. ios::sync_with_stdio(false);
  13. cin.tie(0), cout.tie(0);
  14. int n;
  15. cin >> n;
  16. for (int i = 1; i <= n; i++) {
  17. cin >> arr[i];
  18. }
  19. vector<pii> ans;
  20. for (int i = 1; i <= n; i++) {
  21. while (arr[i] != i) {
  22. ans.push_back(pii(i, arr[i]));
  23. swap(arr[i], arr[arr[i]]);
  24. }
  25. }
  26. cout << ans.size() << endl;
  27. for (auto [u, v] : ans)
  28. cout << u << " " << v << endl;
  29. // system("pause");
  30. return 0;
  31. }

另一种解法:

  1. #include <iostream>
  2. #include <queue>
  3. using namespace std;
  4. int n;
  5. int a[200100];
  6. int p = -1;
  7. int idx[200100];
  8. queue<pair<int, int>> q;
  9. int main() {
  10. cin >> n;
  11. for (int i = 1; i <= n; i++) cin >> a[i];
  12. for (int i = 1; i <= n; i++) {
  13. idx[a[i]] = i;
  14. }
  15. int cnt = 0;
  16. for (int i = 1; i <= n; i++) {
  17. if (a[i] != i) {
  18. cnt++;
  19. q.push({min(idx[i], i), max(idx[i], i)});
  20. int tmp = idx[i];
  21. swap(idx[a[i]], idx[i]);
  22. swap(a[i], a[tmp]);
  23. }
  24. }
  25. cout << cnt << '\n';
  26. while (!q.empty()) {
  27. cout << q.front().first << ' ' << q.front().second << '\n';
  28. q.pop();
  29. }
  30. return 0;
  31. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/523805
推荐阅读
相关标签
  

闽ICP备14008679号