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 s2−1 ,通过 r e v ( s 2 − 1 ) rev(s_2-1) rev(s2−1)
然后,将 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(n−1) 次
代码
#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;
}