[题解]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;
}
posted @ 2024-11-28 21:47  WBIKPS  阅读(50)  评论(0)    收藏  举报