「RHOI-1」似曾相识燕归来 题解
一个重要的观察:将
令
一个经典的结论:对于一个
接下来考虑如何在将
下面默认第
Case 1: n\le 3
特判即可。
Case 2: q_1=n
容易发现这种情况下我们无法移动 -1。
Case 3: q_1=1
容易发现这种情况下我们可以利用
Case 4: \exists \ q_1<i\le n,p_i<p_1
进行一次
Case 5: p_1\ge 3
由于
Case 6: p_1=2,p_2=1,p_i=i\ (3\le i\le n)
此种情况下的最少操作次数为 -1。
Case 7: p_1=2,p_2=1
找到一个
Case 8:p_1=2
若
时间复杂度为
#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;
}