1427D - Unshuffling a Deck 思维构造

本文探讨了一种在有限次数内完成牌堆重组的策略。通过将第i张牌与第n-i+1张进行配对交换,可以在n/2次操作内完成整个牌堆的反转,从而解决1427D问题。具体实现细节见代码实现。
摘要由CSDN通过智能技术生成

这类操作构造问题一般给的操作限制就是上界。

也就是我们要n次换完。很容易想到一次换一个。

由于是反转操作,我们可以i和n-i+1打包一起换。

然后换n/2次即可。

细节见代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define re register
#define ls (o<<1)
#define rs (o<<1|1)
//#define m (l+r)/2
#define pb push_back
typedef pair<int,int> pii;
const double PI= acos(-1.0);
const int M = 1e5+7;
/*
int head[M],cnt=1;
void init(int n){cnt=1;for(int i=0;i<=n;i++)head[i]=0;}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
vector<int>v[M];int sz=0,N;
int id[M];//数字i的下标 
int a[M],b[M];
void gao(int sz){
	int tp=1,n=v[sz].size();
	int L=0,R=N+1;
	int bl=0,br=N+1;
	for(int i=0;i<n/2;i++){
		int nml=v[sz][i],nmr=v[sz][n-i-1];
	//	cout<<sz<<" - "<<nml<<"  "<<nmr<<" "<<n<<endl;
		for(int j=R-nml;j<R;j++){
			b[j]=a[L+j-(R-nml)+1];
		//	cout<<j<<" - > "<<L+j-(R-nml)+1<<endl;
		}
		for(int j=L+1;j<=L+nmr;j++){
			b[j]=a[R-nmr+(j-L-1)];
		//	cout<<j<<" - > "<<R-nmr+(j-L-1)<<endl;
		}
		L+=nml,R-=nmr;
		bl+=nmr,br-=nml;
	}
	if(n&1){
		int nml=v[sz][n/2],nmr=v[sz][n/2];
		for(int i=bl+1;i<=br-1;i++)b[i]=a[L+i-bl];
	}
	for(int i=1;i<=N;i++){
		a[i]=b[i];
		id[a[i]]=i;
	}
//	cout<<" --   ";for(int j=1;j<=N;j++)cout<<a[j]<<" ";cout<<endl;
}
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int n,q;
	cin>>n;
	N=n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		id[a[i]]=i;
	}
	//每次把i和 n-i移动到对应位置,每次移动2个,就不用考虑奇偶对称的问题了 
	for(int i=1;i<=n/2;i++){
		/* 把a->A  ,b -> B
		情况一: XAXaXbXBX
		1:
		X AXa X bXB X
		X bXB X AXa X
		2:
		X b XBXAX a X
		X a XBXAX b X
		
		情况二: XAXbXaXBX
		1:
		X1 AXb X aXB X2
		X2 aXB X AXb X1
		2:
		X1 aXBXAXb X2
		*/
		int ia=id[i],ib=id[n-i+1];
		if(ia==i&&ib==n-i+1)continue;
	//	cout<<i<<" -=-=-=  "<<endl;
	//	cout<<" == ==   "<<ia<<" "<<ib<<endl;
		if(ia<ib){//对应情况一 
			//步数一: 
			++sz;
			if(i-1>0)v[sz].pb(i-1);//当i>1时才有最左边的块 
			v[sz].pb(ia-i+1);
			if(ib-ia-1>0)v[sz].pb(ib-ia-1);
			v[sz].pb(n-i+1-ib+1);
			if(i-1>0)v[sz].pb(i-1);
			/*步数二:
				X b XBXAX a X
				X a XBXAX b X
			*/ 
			gao(sz);//更新变化 
			if(v[sz].size()==1)v[sz].clear(),--sz;//不需要这一步 
			++sz;
			if(i-1>0)v[sz].pb(i-1);
			v[sz].pb(1);
			if(n-i+1-i-1>0)v[sz].pb(n-i+1-i-1);
			v[sz].pb(1);
			if(i-1>0)v[sz].pb(i-1);
			gao(sz);//更新变化 
			if(v[sz].size()==1)v[sz].clear(),--sz;//不需要这一步 
		}else{//对应i情况二 
			/*
			情况二: XAXbXaXBX
			1:
			X AXb X aXB X
			X aXB X AXb X
			2:
			X1 aXBXAXb X2
			*/
			++sz;
			if(i-1>0)v[sz].pb(i-1);
			v[sz].pb(ib-i+1);
			if(ia-ib-1>0)v[sz].pb(ia-ib-1);
			v[sz].pb(n-i+1-ia+1);
			if(i-1>0)v[sz].pb(i-1);
			gao(sz);//更新变化 
			if(v[sz].size()==1)v[sz].clear(),--sz;//不需要这一步 
			++sz;
			if(i-1>0)v[sz].pb(i-1);
			v[sz].pb(n-i+1-i+1);
			if(i-1>0)v[sz].pb(i-1);
			gao(sz);
			if(v[sz].size()==1)v[sz].clear(),--sz;//不需要这一步 
		}
		//cout<<" --   ";for(int j=1;j<=n;j++)cout<<a[i]<<" ";cout<<endl;
	}
	cout<<sz<<endl;
	for(int i=1;i<=sz;i++){
		cout<<v[i].size()<<" ";
		for(auto y:v[i]){
			cout<<y<<" ";
		}
		cout<<endl;
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值