Public NOIP Round #6 D 排序 题解
Description
今天是 YQH 的生日,她得到了一个
YQH 是一个有强迫症的女孩子,她希望把这个排列从小到大排序,具体的,她可以进行这样的操作:
-
把
分成若干个区间,假如是 段,依次为 ,其中 。 -
假如原来的排列为
,那么把排列变为 ,即把每一段看作一个整体,然后把这个排列进行 reverse。
YQH 希望进行尽可能少的操作,把序列从小到大排序。但是她太笨了,所以她找到你帮忙。注意,你不需要得到最小操作数。
Solution
考虑分治。
假设当前已经让
先把连续段缩掉,那么序列变为
那么设
于是总次数为
Code
#include <bits/stdc++.h> // #define int int64_t using vi = std::vector<int>; using vvi = std::vector<std::vector<int>>; const int kMaxN = 2e4 + 5; int n, m; int a[kMaxN], len[kMaxN]; bool b[kMaxN], op[kMaxN]; void prework(int l, int r) { int lst = l - 1; m = 0; for (int i = l; i <= r; ++i) { if (i == r || b[i] != b[i + 1]) { op[++m] = b[i], len[m] = i - lst; lst = i; } } } vvi getvec(int l, int r) { vvi vec; for (;;) { prework(l, r); if (m == 2 && op[1] == 0 && op[2] == 1) break; std::vector<int> v; for (int i = 1, now = 1; i <= m; now = 3 - now) { now = std::min(now, m - i + 1); int s = 0; for (int j = i; j <= i + now - 1; ++j) s += len[j]; v.emplace_back(s); i += now; } vec.emplace_back(v); int now = l; std::reverse(a + l, a + 1 + r); std::reverse(b + l, b + 1 + r); std::reverse(v.begin(), v.end()); for (auto x : v) { std::reverse(a + now, a + now + x); std::reverse(b + now, b + now + x); now += x; } } return vec; } vi merge(vi a, vi b) { vi c; for (auto x : a) c.emplace_back(x); for (auto x : b) c.emplace_back(x); return c; } vvi solve(int l, int r) { if (l == r) return {}; int mid = (l + r) >> 1; if (r - l + 1 > 3 && (~(l + r) & 1)) ++mid; for (int i = l; i <= r; ++i) b[i] = (a[i] > mid); auto vec = getvec(l, r), L = solve(l, mid), R = solve(mid + 1, r); int sz = std::max(L.size(), R.size()); if (sz & 1) ++sz; L.resize(sz, vi{mid - l + 1}); R.resize(sz, vi{r - mid}); for (int i = 0; i < sz; ++i) { if (~i & 1) vec.emplace_back(merge(L[i], R[i])); else vec.emplace_back(merge(R[i], L[i])); } return vec; } void dickdreamer() { std::cin >> n; for (int i = 1; i <= n; ++i) std::cin >> a[i]; auto res = solve(1, n); std::cout << res.size() << '\n'; for (auto &vec : res) { std::cout << vec.size() << ' '; for (auto x : vec) std::cout << x << ' '; std::cout << '\n'; } } int32_t main() { #ifdef ORZXKR freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0); int T = 1; // std::cin >> T; while (T--) dickdreamer(); // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n"; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步