1 条题解
-
0
自动搬运
来自洛谷,原作者为

Ecrade_
算法竞赛打 APIO,就像,只能度过一个相对失败的人生。搬运于
2025-08-24 22:47:33,当前版本为作者最后更新于2023-05-15 21:49:04,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
一个重要的观察:将 调整到首位之后,其余元素可以任意交换位置。
令 为 的逆,记 为 的置换环个数。
一个经典的结论:对于一个 的排列 ,一次操作可以交换其中任意两个数的位置,则至少需要 次操作才能将 升序排列,因为每次交换最多使 减少 。一种可行的交换方案是,从小到大枚举 ,若 ,则交换 和 。
接下来考虑如何在将 用尽量少的操作次数调整到首位的同时,使 尽量大。
下面默认第 个 Case 不包含第 个 Case。
Case 1:
特判即可。
Case 2:
容易发现这种情况下我们无法移动 的位置,故输出
-1。Case 3:
容易发现这种情况下我们可以利用 交换排列中除了 的任意两个数,故此时交换的最少次数为 。
Case 4:
进行一次 的操作即可转换为 Case 3,容易发现总最少操作次数仍为 。
Case 5:
由于 右边的数均比 大,故 左边一定存在一个 使得 ,进行一次 的操作即可转换为 Case 4。由于两次操作后 ,故操作次数 。
Case 6:
此种情况下的最少操作次数为 次,一种可行的方案为 。注意此时若 需输出
-1。Case 7:
找到一个 满足 ,则我们可以进行 三次操作使得 ,故操作次数 。
Case 8:
若 ,进行 两次操作,否则进行 三次操作,由于至多三次操作后 ,故操作次数 。
时间复杂度为 。
#include<bits/stdc++.h> using namespace std; int t,n,l,cnt,p[2000009],q[2000009]; struct st{int x,y,z;}ans[2000009]; inline int read(){ int s = 0,w = 1; char ch = getchar(); while (ch > '9' || ch < '0'){ if (ch == '-') w = -1; ch = getchar();} while (ch <= '9' && ch >= '0') s = (s << 1) + (s << 3) + (ch ^ 48),ch = getchar(); return s * w; } void print(){ if (cnt > l){puts("-1"); return;} printf("%d\n",cnt); for (int i = 1;i <= cnt;i += 1){ printf("%d %d %d\n",ans[i].x,ans[i].y,ans[i].z); } } void add(int x,int y,int z){ if (p[x] > p[z]) swap(p[x],p[y]),swap(q[p[x]],q[p[y]]); else swap(p[y],p[z]),swap(q[p[y]],q[p[z]]); ans[++ cnt] = (st){x,y,z}; } void swapsort(){ for (int i = 1;i <= n;i += 1) if (q[i] != i) add(1,min(i,q[i]),max(i,q[i])); } void work(){ if (n == 1) return; if (q[1] == n){cnt = 1e9; return;} if (n == 2) return; if (q[1] == 1){swapsort(); return;} if (n == 3){ if (p[1] == 2) cnt = 1e9; else add(1,2,3),add(1,2,3); return; } int pos = q[1]; for (int i = pos + 1;i <= n;i += 1) if (p[i] < p[1]){ add(1,pos,i),swapsort(); return; } if (p[1] >= 3){ for (int i = 2;i < pos;i += 1) if (p[i] < p[1]){ add(1,i,n),add(1,pos,n),swapsort(); return; } return; } if (p[2] == 1){ for (int i = 3;i < n;i += 1) if (p[i] > p[i + 1]){ add(1,2,i),add(1,2,i),add(1,i,i + 1),swapsort(); return; } add(1,2,3),add(1,2,3),add(1,2,4),add(1,3,4),add(1,2,4); return; } if (q[n] > 2) add(1,2,q[n]); add(1,2,pos),add(1,pos,n),swapsort(); } int main(){ t = read(); while (t --){ n = read(),l = read(),cnt = 0; for (int i = 1;i <= n;i += 1) p[i] = read(); for (int i = 1;i <= n;i += 1) q[p[i]] = i; work(),print(); } return 0; }
- 1
信息
- ID
- 8137
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者