构造题练习\(CF2052A.\ Adrenaline\ \ Rush\)
链接
思路
-
遇到一个逆序对要完成一次超车,遇到一个正序对可以看成先超车然后又被超回来了,所以完成了两次超车,最多的超车次数很好求
-
比较难的是按顺序求出超车的序列
-
一个想法是按照最终的序列从最后一辆车开始往前处理,找到它在最初序列中的位置一直向前超车,到达第一个,然后被别的车超到达它应该在的位置
- 为什么要从最后一个开始处理呢?这样处理其他车的时候就不用考虑它的影响了
- 过程中需要记录每一个车的实时位置,和每一个位置是哪一辆车
- 举个例子
- 给定序列 1 2 4 3,根据题意每辆车的初始位置1 2 3 4
- 从最后一个开始处理,最后一个位置是车3,它初始位置是位置3
- 那么从位置3往前面超,一直到第一个 3 1 2 4,然后被后面的车超到应在的位置 1 2 4 3
- ......
代码
#pragma optimize GCC(2)
#pragma optimize GCC(3)
#pragma optimize GCC("Ofast")
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define lowbit(x) x & -x
using i64 = long long;
using u64 = unsigned long long;
using ld = long double;
const int maxn = 2e5 + 5;
const int inf = 0x7f7f7f7f;
const int mod = 1e9 + 7;void solve()
{int n = 0;std::cin >> n;std::vector<int> nums(n + 1, 0);std::vector<int> pos(n + 1, 0), mp(n + 1, 0);// pos[i], i这个数在哪一个位置// mp[i], i这个位置是哪一个数for (int i = 1; i <= n; i++){std::cin >> nums[i];pos[i] = i;mp[i] = i;}std::vector<std::pair<int, int>> res;for (int to = n; to >= 1; to--){int t = nums[to];int p = pos[t];for (int i = p - 1; i >= 1; i--){res.push_back({t, mp[i]});pos[t] = i;pos[mp[i]] = i + 1;mp[i + 1] = mp[i];mp[i] = t;}for (int i = 2; i <= to; i++){res.push_back({mp[i], t});pos[t] = i;pos[mp[i]] = i - 1;mp[i - 1] = mp[i];mp[i] = t;}}std::cout << res.size() << endl;for (auto [x, y] : res){std::cout << x << " " << y << endl;}
}signed main()
{std::ios::sync_with_stdio(false);std::cin.tie(nullptr); std::cout.tie(nullptr);//freopen("out.txt", "w", stdout);int t = 1;// std::cin >> t;while(t--){solve();}return 0;
}