lg9347题解
先特判掉\(n\leq 4\)的情况,用bfs求解。
对于其他情况显然\(a_n=1\)无解,因为无论此时怎么操作\(a_n\)都会\(=1\)
对于这道题,如果\(a_1=1\),显然可以用最多\(n-2\)次操作还原数组:
考虑从大到小归位,设归位到\(x\)(位置为\(y\)),如果\(x!=y\)那么操作\(1,y,x\)。由于\(1\)最小,\(>x\)的数已经归位,所以\(1<a_y<x\)。
考虑\(i \to a_i\)连边,每次操作等于从这些边构成的环上删除一个点,当某个环大小为\(1\)则不用删除,所以次数为\(\sigma 环长-1\)=\(n-环的个数\),而由于\(a_1=1\),环至少有\(2\)个,所以最多操作\(n-2\)次。
考虑\(n+1\)次做法:(假设\(a_1!=1\),\(a_1=1\)可以进行前面的操作)
当\(n>4\),考虑不断删除数组末尾满足\(a_n=n,a_{n-1}!=1\)的数\(n\),每删除一个\(n\)就\(-1\)
如果\(1\)左边有数\(>1\)右边的数,则设\(1\)左边数最大值是\(mx\),右边最小数的最小值是\(mn\)。
当\(mx>mn时\)操作\((1,mx的位置,1的位置)\)(显然\(a_1>1\))让\(a_1=mx>mn\),再操作\(1,1的位置,mn的位置\)让\(a_1=1\),然后就能操作\(n-2\)次排序整个数组。
否则如果\(a_1=2,a_2=1\),则操作\(1,2,n的位置\)(由于前面的假设,\(n的位置!=n\),否则\(a_{n-1}=1\),数组长度只有\(3\))会让\(n\)在\(1\)的左边,此时\(mx=n>mn\)。
在进行上面的判定后\(n>1的位置>2\),则可以选择操作\(1的位置-2,1的位置-1,1的位置+1\)。,由于\(a_{1的位置+1}>mx>a_{1的位置-2}\),操作后\(a_{1的位置-1}>mx\),此时可以转化为\(mx<mn\)的情况。
考虑优化。注意到\(a_1=2,a_2=1\)时,上面的操作只需\(O(n)\)次,因为在\(1\)归位后\(2\)也会归位,至少有\(3\)个环,所以操作次数为\(n-3+3=n\)。
当\(a_1=1的位置\),此时考虑操作\(1,a_1-1的位置,n\),再操作
#include<bits/stdc++.h>
using namespace std;
#define N 2000010
struct no{
int a[10];
};
int operator <(no x,no y){
for(int i=1;i<9;i++){
if(x.a[i]<y.a[i])
return 0;
else if(x.a[i]>y.a[i])
return 1;
}
return 0;
}
int operator !=(no x,no y){
for(int i=1;i<9;i++)
if(x.a[i]!=y.a[i])
return 1;
return 0;
}
map<no,int>s,xx,yy,zz;
map<no,no>pr;
set<no>st;
queue<no>q;
no cz(no a,int x,int y,int z){
if(a.a[x]>a.a[z])
swap(a.a[x],a.a[y]);
else
swap(a.a[y],a.a[z]);
return a;
}
int n,l,p[N],po[N],T,x[N],y[N],z[N],tp;
void ad(int a,int b,int c){
x[++tp]=a;
y[tp]=b;
z[tp]=c;
}
void sw(int x,int y){
swap(po[p[x]],po[p[y]]);
swap(p[x],p[y]);
}
void doit(){
int mx=0,mn=1e9+1;
for(int i=1;i<po[1];i++)
mx=max(mx,p[i]);
for(int i=po[1]+1;i<=n;i++)
mn=min(mn,p[i]);
if(po[mx]!=1){
ad(1,po[mx],po[1]);
sw(1,po[mx]);
}
ad(1,po[1],po[mn]);
sw(1,po[1]);
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&l);
tp=0;
for(int i=1;i<=n;i++){
scanf("%d",&p[i]);
po[p[i]]=i;
}
if(n==1){
puts("0");
continue;
}
if(p[n]==1){
puts("-1");
continue;
}
if(p[1]==2&&p[2]==1&&n==3){
puts("-1");
continue;
}
if(n==4&&l==n&&p[1]==2&&p[2]==1&&p[3]==3&&p[4]==4){
puts("-1");
continue;
}
while(p[n]==n&&n>4&&p[n-1]!=1)
n--;
if(n==4){
no t;
for(int i=0;i<10;i++)
t.a[i]=0;
for(int i=1;i<=4;i++)
t.a[i]=p[i];
q.push(t);
s[t]=0;
st.insert(t);
while(!q.empty()){
no x=q.front();
q.pop();
for(int i=1;i<5;i++)
for(int j=i+1;j<5;j++)
for(int k=j+1;k<5;k++){
no nx=cz(x,i,j,k);
if(!st.count(nx)){
st.insert(nx);
s[nx]=s[x]+1;
pr[nx]=x;
xx[nx]=i;
yy[nx]=j;
zz[nx]=k;
q.push(nx);
}
}
}
no tt=(no){0,1,2,3,4};
while(tt!=t){
x[++tp]=xx[tt];
y[tp]=yy[tt];
z[tp]=zz[tt];
tt=pr[tt];
}
reverse(x+1,x+tp+1);
reverse(y+1,y+tp+1);
reverse(z+1,z+tp+1);
printf("%d\n",tp);
for(int i=1;i<=tp;i++)
printf("%d %d %d\n",x[i],y[i],z[i]);
st.clear();
s.clear();
pr.clear();
xx.clear();
yy.clear();
zz.clear();
continue;
}
if(p[1]!=1){
if(p[1]==2&&p[2]==1){
if(p[n]!=n){
ad(1,2,po[n]);
sw(2,po[n]);
}
else{
ad(1,2,3);
sw(2,3);
}
}
int mx=0,mn=1e9;
for(int i=1;i<po[1];i++)
mx=max(mx,p[i]);
for(int i=po[1]+1;i<=n;i++)
mn=min(mn,p[i]);
if(mx>mn)
doit();
else{
if(p[1]==po[1]){
ad(1,po[p[1]-1],n);
sw(po[p[1]-1],n);
ad(1,po[1],n);
sw(1,po[1]);
}
else{
ad(p[1]-1,p[1],po[1]+1);
sw(p[1],po[1]+1);
doit();
}
}
}
for(int i=n;i;i--){
if(p[i]==i)
continue;
ad(po[1],po[i],i);
sw(po[i],i);
}
printf("%d\n",tp);
for(int i=1;i<=tp;i++)
printf("%d %d %d\n",x[i],y[i],z[i]);
puts("");
}
}