F. Cyclic Shifts Sorting(模拟&排序)
传送门
思路: 模拟冒泡排序,只不过两个数交换,变成了三个数进行位置转换。
显然三个数可以顺时针走,也可以逆时针走。
我们可以第轮将当前最小的数移动到位置,
因为每操作一次,第三个数可以移动到第一个数的位置。
如果当前最小的数与位置的距离不是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; }