CF1561E - Bottom-Tier Reversals——有趣的构造题

看题解才做出来,整理一下。

第一步

由于只能翻转奇数前缀,所以对于所有数翻转前后下标奇偶性不变
通过此,判断如果 \(i\) 的奇偶性异于 \(a_i\) 的奇偶性,则无解。

第二步

由于只能翻转 \(a_i\) 为奇数的前缀,所以猜想相邻的两个数一起考虑,即:先处理 \(1,2\),让它们处理完后变成 xxxx,2,1;再处理 \(3,4\),……;再处理 \(2i-1,2i\),让它们处理完后变成 xxxx,2i,2i-1,2i-2,2i-3,...,2,1;最后处理 \(n-2,n-1\),那么已经不需要处理 \(n\) 了,最后排成 n,n-1,...,2,1,只需再用一次翻转操作翻转整个数列。
通过此,猜想每一步至多翻 5 次,因为 \(5\lfloor\frac{n}{2}\rfloor+1\le\frac{5n}{2}\),6 就不行了。

第三步(翻转策略)

假如现在是这么一个状态
xxx,2i-1,xxx,2i,xxx,2i-2,...,2,1
为了叙述方便,记 \(p1,p2\)\(2i-1,2i\) 的位置。

  1. 翻转 \([1,p1]\)2i-1,xxx,2i,xxx,2i-2,...,2,1
  2. 翻转 \([1,p2-1]\)xxx,2i-1,2i,xxx,2i-2,...,2,1
  3. 翻转 \([1,p2+1]\)x,2i,2i-1,xxx,2i-2,...,2,1
    这里做一解释,由于 \(2i\) 此时坐标为偶,所以翻的是 \(p2+1\),由于 \(2i-2\) 的坐标也是偶的,所以 \(2i\)\(2i-2\) 之间肯定有一个 x(代表不相干数),因此不会影响到 \(2i-2\) 那一块。
  4. 翻转 \([1,3]\)2i-1,2i,x,xxx,2i-2,...,2,1
  5. 最后,翻转 \([1,pos(2i-2)-1]\)(\(pos\) 代指数值的位置):xxx,2i,2i-1,2i-2,...,2,1

共 5 次。
可以自己思考一下 xxx,2i,xxx,2i-1,xxx,2i-2,...,2,1 的情况,操作序列是不变的,但注意 \(p1,p2\) 在每一次翻转之后是可能发生变化的

代码

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N=2025;
int n,a[N],pos[N];
void rev(int m){
	printf("%d ",m);
	for(int i=1;i<=m/2;i++)swap(a[i],a[m-i+1]);
	for(int i=1;i<=m;i++)pos[a[i]]=i;
}
void solve(){
	cin>>n;
	bool noans=0;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(a[i]&1^i&1)noans=1;
		pos[a[i]]=i;
	}
	if(noans){puts("-1");return;}
	cout<<n/2*5+1<<'\n';
	pos[0]=n+1;
	for(int i=1;i<n;i+=2){
		rev(pos[i]),rev(pos[i+1]-1),rev(pos[i+1]+1),rev(3),rev(pos[i-1]-1);
	}
	printf("%d\n",n);
}
int main(){
	int t;cin>>t;while(t--)solve();
}
想想看,这个为什么错了
#include <bits/stdc++.h>
using namespace std;
const int N=2025;
int n,a[N],pos[N];
void rev(int m){
	for(int i=1;i<=m/2;i++)swap(a[i],a[m-i+1]);
	for(int i=1;i<=m;i++)pos[a[i]]=i;
}
void solve(){
	cin>>n;
	bool noans=0;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(a[i]&1^i&1)noans=1;
		pos[a[i]]=i;
	}
	if(noans){puts("-1");return;}
	cout<<n/2*5+1<<'\n';
	pos[0]=n+1;
	for(int i=1;i<n;i+=2){
		printf("%d %d %d %d %d ",pos[i],pos[i+1]-1,pos[i+1]+1,3,pos[i-1]-1);
		rev(pos[i]),rev(pos[i+1]-1),rev(pos[i+1]+1),rev(3),rev(pos[i-1]-1);
	}
	printf("%d\n",n);
}
int main(){
	int t;cin>>t;while(t--)solve();
}
posted @ 2021-11-12 15:40  pengyule  阅读(47)  评论(0)    收藏  举报