链接

思路

  1. 遇到一个逆序对要完成一次超车,遇到一个正序对可以看成先超车然后又被超回来了,所以完成了两次超车,最多的超车次数很好求

  2. 比较难的是按顺序求出超车的序列

  3. 一个想法是按照最终的序列从最后一辆车开始往前处理,找到它在最初序列中的位置一直向前超车,到达第一个,然后被别的车超到达它应该在的位置

  • 为什么要从最后一个开始处理呢?这样处理其他车的时候就不用考虑它的影响了
  • 过程中需要记录每一个车的实时位置,和每一个位置是哪一辆车
  • 举个例子
    1. 给定序列 1 2 4 3,根据题意每辆车的初始位置1 2 3 4
    2. 从最后一个开始处理,最后一个位置是车3,它初始位置是位置3
    3. 那么从位置3往前面超,一直到第一个 3 1 2 4,然后被后面的车超到应在的位置 1 2 4 3
    4. ……

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#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;
}