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

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

傳送門
思路: 模擬冒泡排序,只不過兩個數交換,變成了三個數進行位置轉換。

顯然三個數可以順時針走,也可以逆時針走()(順時針操作兩次等價於逆時針操作一次)

我們可以第ii輪將當前最小的數移動到位置ii

因爲每操作一次,第三個數可以移動到第一個數的位置。

如果當前最小的數與位置ii的距離不是2的倍數,我們需要讓位置pospos操作一次,使其變爲pos+1pos+1,然後再不斷進行操作fun(pos2),pos=2fun(pos-2),pos-=2 就可以了。

這裏需要注意特判一下,如果當前最小的數在最後一個,直接操作位置n2n-2

這樣可以在距離不是22的倍數時,向前移動一個位置。

這樣我們就可以排好1n21\sim n-2

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

否則我們需要將a[n1],a[n]a[n-1],a[n]交換一下位置。

如果a[n2]=a[n]a[n-2]=a[n],我們只需對位置n2n-2操作一次即可。

對於其他情況,顯然如果我們只對最後三個數進行操作,無論怎麼操作都只會改變相對位置,不會使兩個數交換,所以我們要使a[n1],a[n]a[n-1],a[n]交換,我們必須要使a[n2],a[n1]a[n-2],a[n-1]交換纔行,一直遞歸,我們必須在前n2n-2個數找到兩個相同的數纔行。

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

顯然我們可以對位置1,21,2分別操作兩次(也就是逆時針移動)即可使a3,a4a_3,a_4交換。

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

時間複雜度:O(n2)O(n^2)

#include<bits/stdc++.h>
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<int,int>
#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章