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("");
	}
}
posted @ 2023-07-14 21:57  celerity1  阅读(7)  评论(0)    收藏  举报