CF1561E Bottom-Tier Reversals

CF1561E Bottom-Tier Reversals

思路

首先,可以发现交换不会改变一个数的位置的奇偶性,即一个数交换前后的位置的奇偶性相同

所以如果奇数位出现了偶数一定不成立,反之亦然

那么先猜测其余情况一定有解,尝试构造一下

首先,我们非常想先让最大的数回到自己的位置,这样,以后的翻转就不用考虑最大数那一位

然后发现,只有次大的数无法自己回到自己的位置,因为次大的数一定是偶数(保证n是奇数),而翻转序列的长度需要是奇数

那么当尝试将次大的数放回自己的位置时,最大的数的位置又发生了变动,这是我们非常不想看到的

那么,我们尝试让最大的数和次大的数同时回到自己的位置

以下给出一种构造法

不妨设最大的数位置为 s 1 s_1 s1 ,次大的数位置为 s 2 s_2 s2

r e v ( x ) rev(x) rev(x) 为翻转 1 到 x 这一段序列

首先,将 s 1 s_1 s1 翻转到 1 ,通过 r e v ( s 1 ) rev(s1) rev(s1)

然后,将 s 1 s_1 s1 翻转到 s 2 − 1 s_2-1 s21 ,通过 r e v ( s 2 − 1 ) rev(s_2-1) rev(s21)

然后,将 s 1 s_1 s1 翻转到 3 ,通过 r e v ( s 2 + 1 ) rev(s_2+1) rev(s2+1)

然后,将 s 1 s_1 s1 翻转到 1 ,通过 r e v ( 3 ) rev(3) rev(3)

最后,将 s 1 s_1 s1 翻转到 n n n ,通过 r e v ( n ) rev(n) rev(n)

总共花费 5 次,将两个点放回了自己的位置,最多花费 5 ( n − 1 ) 2 \frac{5(n-1)}{2} 25(n1)

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef const int& cint;

const int mod = 1e9+7;
const int inf_int = 0x7fffffff;
const ll inf_ll = 0x7fffffffffffffff;
const double ept = 1e-9;

int t, n;
int a[2030];
vector<int> ans;

int reserve(cint x, cint st) {
    if(x == 1) return 0;
    ans.push_back(x);
    for(int i=x; i>x/2; i--) {
        swap(a[i], a[x-i+1]);
    }
}

int main() {
    cin >> t;
    while(t--) {
        cin >> n;
        bool flag = 0;
        for(int i=1; i<=n; i++) {
            cin >> a[i];
            if((a[i]&1) != (i&1)) flag = 1;
        }
        ans.clear();
        if(!flag)
        for(int i=n; i>1; i-=2) {
            int s1, s2;
            for(int j=1; j<=i; j++) {
                if(a[j] == i) s1 = j;
                if(a[j] == i-1) s2 = j;
            }
            if(s1 != 1) {
                reserve(s1, i-1);
                for(int j=1; j<=i; j++)
                    if(a[j] == i-1) s2 = j;
            }
            if(s2 != 2) {
                reserve(s2-1, 1);
                reserve(s2+1, 1);
                reserve(3, 1);
            }
            reserve(i, 1);
        }
        if(flag) cout << -1 << endl;
        else {
            cout << ans.size() << endl;
            for(int v: ans) {
                cout << v << ' ';
            }
            cout << endl;
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值