LOJ #2158. 「POI2011 R1」移方块 Shift(构造)

博客详细讨论了LOJ #2158「POI2011 R1」移方块(Shift)问题的解决策略。通过AAB和ABB操作分析,解释如何将序列中的元素有效移动,并指出在特定情况下(i>n-2)需要特殊处理以避免无解的情况。鼓励读者尝试自己完成解决方案。

题目

我太难了。
发现把第三个放到开头有点鬼畜。
我们来把这个操作规约到我们熟悉的操作。
做一次 A A B AAB AAB
我们得到了什么?把 [ 2 , n ] [2,n] [2,n]每个数向后移两个位置。
所以我们可以从 i = [ 2 , n ] i=[2,n] i=[2,n]依次把 i i i移到 1 1 1,然后把 1.2.3.. i − 1 1.2.3..i-1 1.2.3..i1这个之前已经排好序的序列用 A A B AAB AAB移到整个序列的最后,如果我们把 i − 1 i-1 i1移到了 n − 1 n-1 n1的位置,我们可以用 A B B ABB ABB i − 1 i-1 i1移到 n n n
这个方法在 i < = n − 2 i<=n-2 i<=n2时都没有问题。
但是在 i > n − 2 i>n-2 i>n2 A B B ABB ABB就行不通了。
所以我们需要在这个时候特判,顺便判断无解。
读者自主完成不难。
A C   C o d e \mathrm{AC \ Code} AC Code

#include<bits/stdc++.h>
#define maxn 2005
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
#define pii pair<int,int>
#define mp make_pair
#define pb emplace_back
using namespace std;

int n,a[maxn];
inline int find(int b){ rep(i,1,n) if(a[i]==b) return i; }
vector<pii >ans,a2;
inline void arg(int l,int r,int t){ static int b[maxn];
	rep(i,l,r) b[(i-l+t)%(r-l+1)+l]=a[i];
	rep(i,l,r) a[i]=b[i]; }
int main(){
	scanf("%d",&n);
	rep(i,1,n) scanf("%d",&a[i]);
	rep(i,2,n-2){
		int p=find(i);
		if(a[(p+n-2)%n+1]==i-1) continue;
		if(p^1)	ans.pb(mp(0,n+1-p)),arg(1,n,n+1-p);
		p=find(i-1);
		if(p^n){
			rep(j,1,(n-p)/2) ans.pb(mp(0,2)),ans.pb(mp(1,1));
			bool flg = 0;
			if((n-p)&1) ans.pb(mp(0,1)),ans.pb(mp(1,2)),flg=1;
			arg(2,n,n-p);
			if(flg)
				swap(a[2],a[3]);
		}
	}
	if(n&1){
		int p=find(n-1);
		if(a[(p+n-2)%n+1] ^ (n-2)){ puts("NIE DA SIE");return 0;}
	}
		int p=find(n);
		if(a[(p+n-2)%n+1]^(n-1)){
			if(p^1)	ans.pb(mp(0,n+1-p)),arg(1,n,n+1-p);
			p=find(n-1);
			if(p^n){
				rep(j,1,(n-p)/2) ans.pb(mp(0,2)),ans.pb(mp(1,1));
				arg(2,n,n-p);
			}
		}
		p=find(1);
		if(p^1) ans.pb(mp(0,n+1-p));
	
	int cnt = 0;
	for(int i=0;i<ans.size();i++)
		if(i==ans.size()-1 || ans[i].first ^ ans[i+1].first){
			if(ans[i].second % n != 0)
			a2.pb(ans[i]);
		}
		else 
			ans[i+1].second += ans[i].second;
	printf("%d\n",a2.size());
	for(int i=0;i<a2.size();i++)
				printf("%d%c%c",a2[i].second%n,a2[i].first?'b':'a'," \n"[i==a2.size()-1]);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值