[题解]CF1374F Cyclic Shifts Sorting
与 @Zelotz duel,苦战 129min AC。
思路
(本文中默认字符的大小顺序为:\(a < b < c < \dots\))
首先发现不关心最后两个数是否合法,将前 \(n - 2\) 个位置变得递增是容易的。具体的,对于每一个位置 \(i\),在最终的序列中的值记为 \(t_i\),那么在当前序列中找到一个位置 \(x\),使得 \(a_x = t_i\)。这时候我们就可以将 \(x\) 暴力往前跳,需要注意的是当 \(x,i\) 奇偶不同时,在最后一步需要操作两次。
若现在最后两个数 \(a \leq b\) 则直接合法了,否则只需考虑将最后两个数交换一下。手玩一下 \(n = 3\) 的样例,注意到形如 aba 的串只需操作一次 \(1\) 即可合法。推广到 \(n \geq 3\),若最后三位形如 aba 则通过操作一次 \(n - 2\) 即可。
其次,观察最后一个样例,它出现了形如 aacb 的结构,通过操作两次 \(1\),两次 \(2\) 将串变成了 aabc。这启示我们如果能让 cb 贴上一个 aa,就可以换成 bc。
不妨找到一个 \(id\) 使得 \(a_{id - 1} = a_{id}\),若找不到一定无解。我们只需将最后两个数移动到 \(id + 1,id + 2\) 的位置上,做一次 aacb,然后再移回去。
具体的,你发现若两个点 \(x \leq y\) 奇偶性相同,则 \(y\) 能通过一直操作达到 \(x\);否则,需要调整一下 \(y\) 的奇偶再移动。若 \(id + 1\) 和 \(n - 1\) 奇偶不同,操作两次 \(n - 2\),即可将最后两个数分别移到 \(n - 2,n - 1\),此时可以直接移动。
若回来的时候奇偶不同,同理操作两次 \(id\) 再移动即可。因为前面将 \(n - 2\) 个数操作的步数带 \(\frac{1}{2}\) 的常数,所以若有解按照上述操作方式一定能在 \(n^2\) 次操作中变化成功。
Code
#include <bits/stdc++.h>
#define re register
using namespace std;
const int N = 510;
int n;
int arr[N],tmp[N];
vector<int> ans;
inline int read(){
int r = 0,w = 1;
char c = getchar();
while (c < '0' || c > '9'){
if (c == '-') w = -1;
c = getchar();
}
while (c >= '0' && c <= '9'){
r = (r << 3) + (r << 1) + (c ^ 48);
c = getchar();
}
return r * w;
}
inline void move(int x){
ans.push_back(x);
int a = arr[x],b = arr[x + 1],c = arr[x + 2];
arr[x] = c; arr[x + 1] = a; arr[x + 2] = b;
}
inline void gopre(int a,int b){
while (a - 2 >= b) move(a - 2),a -= 2;
if (a != b) move(b),move(b);
}
inline void gonxt(int a,int b){
while (a != b) move(a),move(a),a += 2;
}
inline void solve(){
ans.clear(); n = read();
for (re int i = 1;i <= n;i++) arr[i] = tmp[i] = read();
sort(tmp + 1,tmp + n + 1);
for (re int i = 1;i <= n - 2;i++){
int id = 0;
for (re int j = i;j <= n;j++){
if (arr[j] == tmp[i]){
id = j; break;
}
}
gopre(id,i);
}
if (arr[n - 1] > arr[n]){
if (arr[n] == arr[n - 2]) move(n - 2);
else{
int id = -1;
for (re int i = 1;i < n;i++){
if (arr[i] == arr[i + 1]) id = i + 2;
}
if (!~id) return puts("-1"),void();
int a = n - 1,b = n;
if ((n - 1) % 2 != id % 2){
move(n - 2); move(n - 2);
a = n - 2; b = n - 1;
}
gopre(a,id); gopre(b,id + 1);
move(id - 2); move(id - 2);
move(id - 1); move(id - 1);
if ((n - 1) % 2 == id % 2){
gonxt(id + 1,n); gonxt(id,n - 1);
}
else{
move(id - 1); move(id - 1);
gonxt(id,n); gonxt(id - 1,n - 1);
}
}
}
if (ans.size() > n * n) puts("-1");
else{
printf("%d\n",ans.size());
for (int x:ans) printf("%d ",x); puts("");
}
}
int main(){
int T; T = read();
while (T--) solve();
return 0;
}

浙公网安备 33010602011771号