题解:P7015 [CERC2013] Crane
Bc2_Ch1ckenPr1nce · · 题解
感觉像诈骗题,一开始把所有排序全部想了一遍,从冒泡到归并,结果发现不符合题目要求 /kel。
我们需要把排列排成
一个很自然的想法是从左往右依次把数字
设数字
关键是怎么选这个区间:设距离
新的距离变成
这时候有人问了,为什么不会破坏已经固定的前缀?关键在于构造保证了
实际操作时,每次交换就是做
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
const int kMaxN = 3e5 + 10;
ll n, a[kMaxN], pos[kMaxN];
vector<pair<ll, ll>> ans;
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t;
for (cin >> t; t; -- t) {
fill(pos + 1, pos + n + 1, 0);
ans.clear();
cin >> n;
for (int i = 1; i <= n; ++ i) {
cin >> a[i], pos[a[i]] = i;
}
for (int x = 1; x <= n; ++ x) {
for (ll p, d, k, l, r; pos[x] > x; ) {
p = pos[x], d = p - x, k = (d + 1) / 2, l = p - 2 * k + 1, r = p;
ans.push_back({l, r});
for (int t = 0, i, j, u, v; t < k; ++ t) {
i = l + t, j = l + k + t, u = a[i], v = a[j];
swap(a[i], a[j]);
pos[u] = j, pos[v] = i;
}
}
}
cout << ans.size() << '\n';
for (auto i : ans) {
cout << i.first << ' ' << i.second << '\n';
}
}
return 0;
}