F. Cyclic Shifts Sorting(模拟&排序)

F. Cyclic Shifts Sorting(模拟&排序)

传送门
思路: 模拟冒泡排序,只不过两个数交换,变成了三个数进行位置转换。

显然三个数可以顺时针走,也可以逆时针走 ( 顺 时 针 操 作 两 次 等 价 于 逆 时 针 操 作 一 次 ) (顺时针操作两次等价于逆时针操作一次) ()

我们可以第 i i i轮将当前最小的数移动到位置 i i i

因为每操作一次,第三个数可以移动到第一个数的位置。

如果当前最小的数与位置 i i i的距离不是2的倍数,我们需要让位置 p o s pos pos操作一次,使其变为 p o s + 1 pos+1 pos+1,然后再不断进行操作 f u n ( p o s − 2 ) , p o s − = 2 fun(pos-2),pos-=2 fun(pos2),pos=2 就可以了。

这里需要注意特判一下,如果当前最小的数在最后一个,直接操作位置 n − 2 n-2 n2

这样可以在距离不是 2 2 2的倍数时,向前移动一个位置。

这样我们就可以排好 1 ∼ n − 2 1\sim n-2 1n2

接下来特判一下如果 a [ n − 1 ] ≤ a [ n ] a[n-1]\leq a[n] a[n1]a[n] 不用再操作了。

否则我们需要将 a [ n − 1 ] , a [ n ] a[n-1],a[n] a[n1],a[n]交换一下位置。

如果 a [ n − 2 ] = a [ n ] , a[n-2]=a[n], a[n2]=a[n]我们只需对位置 n − 2 n-2 n2操作一次即可。

对于其他情况,显然如果我们只对最后三个数进行操作,无论怎么操作都只会改变相对位置,不会使两个数交换,所以我们要使 a [ n − 1 ] , a [ n ] a[n-1],a[n] a[n1],a[n]交换,我们必须要使 a [ n − 2 ] , a [ n − 1 ] a[n-2],a[n-1] a[n2],a[n1]交换才行,一直递归,我们必须在前 n − 2 n-2 n2个数找到两个相同的数才行。

e p : a 1 = 1 , a 2 = 1 , a 3 = 3 , a 4 = 2 ep:a_1=1,a_2=1,a_3=3,a_4=2 ep:a1=1,a2=1,a3=3,a4=2.

显然我们可以对位置 1 , 2 1,2 1,2分别操作两次(也就是逆时针移动)即可使 a 3 , a 4 a_3,a_4 a3,a4交换。

1 , 1 , 3 , 2 → 1 , 3 , 1 , 2 → 1 , 1 , 2 , 3 1,1,3,2\rightarrow 1,3,1,2\rightarrow 1,1,2,3 1,1,3,21,3,1,21,1,2,3.

时间复杂度: O ( n 2 ) O(n^2) O(n2)

#include
using namespace std;
typedef long long ll;
const int N=5e2+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair
#define fi first 
#define se second
vector<int>ans;
int a[N];
void fun(int i){
	ans.push_back(i);
	swap(a[i],a[i+2]),swap(a[i+1],a[i+2]);
} 
int main(){
	int  t;
	scanf("%d",&t);
	while(t--){
	int n;
	scanf("%d",&n);
	ans.clear(); 
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	for(int i=1;i<=n-2;i++){
		int pos=i;
		for(int j=i;j<=n;j++) 
		if(a[j]<a[pos]) pos=j;
		if(pos==n) pos-=2,fun(pos);
		if((pos-i)&1) fun(pos-1),pos++;
		while(pos>i) pos-=2,fun(pos);
	}
	if(a[n-1]>a[n]) {
		if(a[n-2]==a[n]) fun(n-2);
		else {
		for(int i=1;i<n-2;i++) if(a[i]==a[i+1]){
			for(int j=i;j<=n-2;j++) fun(j),fun(j);
			break;
		}
			}
	}
	if(a[n-1]>a[n]){
		puts("-1");
		continue;
	}
	printf("%d\n",ans.size());
	for(auto i:ans) printf("%d ",i);
	puts("");
	} 
	return 0;
}

你可能感兴趣的:(排序,模拟)