当前位置: 首页 > 工具软件 > deck > 使用案例 >

D. Unshuffling a Deck (构造)

罗伟志
2023-12-01

D. Unshuffling a Deck (构造)

思路:构造。

考虑每次操作都对一个数排到对应的位置,这样最多操作 n n n次。

n n n为偶数时,按照 n , 1 , n − 1 , 2 … n,1,n-1,2\dots n,1,n1,2的顺序操作。

n n n为奇数时,按照 1 , n , 2 , n − 1 … 1,n,2,n-1\dots 1,n,2,n1的顺序操作。

这样根据翻转和奇偶性,最后之前排好的位置仍然是排好的。

设一开始未排好的区间为 [ l , r ] = [ 1 , n ] [l,r]=[1,n] [l,r]=[1,n],每次排好一个数就减小区间范围。

比如排好了数 l l l,则区间变为 [ l + 1 , r ] [l+1,r] [l+1,r],排好了 r r r区间就变为了 [ l , r − 1 ] [l,r-1] [l,r1]

直到排好所有数为止。

注意要去除掉分块的个数小于 2 2 2的操作,因为题目要求每次操作最少将数组分为两块。

举个例子:
n = 4 。 n=4。 n=4
初始序列为: 3 , 1 , 2 , 4 3,1,2,4 3,1,2,4
1. [ 1 , 4 ] [1,4] [1,4]操作的数为: 4 4 4,分块为: 3 , 1 3,1 3,1
序列变为: 4 , 3 , 1 , 2 4,3,1,2 4,3,1,2
2. [ 1 , 3 ] [1,3] [1,3]操作的数为: 1 1 1,分块为: 1 , 1 , 2 1,1,2 1,1,2
序列变为: 1 , 2 , 3 , 4 1,2,3,4 1,2,3,4
3. [ 2 , 3 ] [2,3] [2,3](注意这里其实已经排好了,但是我们按照构造的思路会对每个数进行操作).
操作的数为; 3 3 3,分块: 1 , 1 , 1 , 1 1,1,1,1 1,1,1,1
序列变为: 4 , 3 , 2 , 1 4,3,2,1 4,3,2,1
4. [ 2 , 2 ] [2,2] [2,2],操作的数为: 2 2 2,分块: 1 , 1 , 1 , 1 1,1,1,1 1,1,1,1
序列变为: 1 , 2 , 3 , 4 1,2,3,4 1,2,3,4

具体看代码。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=55,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define reg register
#define PII pair<int,int>
#define pb push_back
int n,a[N],b[N];
vector<int>ans[N];
void fun(int tot){
	int k=n,cnt=0;
	for(int i=ans[tot].size()-1;~i;i--){
		for(int j=k-ans[tot][i]+1;j<=k;j++)
			b[++cnt]=a[j];
		k-=ans[tot][i];
	}
	for(int i=1;i<=n;i++) a[i]=b[i];
	//printf("\n-------------\n");
}
int solve(){
	int l=1,r=n,flag=n%2,tot=0,k;
	while(l<=r){
		k=flag?l:r;
		ans[tot].clear();
		for(int i=1;i<=n;i++){
			if(a[i]<l||a[i]>r) ans[tot].pb(1);
			else {
				int j=i,pos;
				for(;j<=n&&a[j]>=l&&a[j]<=r;j++)
					if(a[j]==k)	pos=j;
				if(pos!=i) ans[tot].pb(pos-i);
				ans[tot].pb(j-pos);
				i=j-1;
			}
		}
		if(flag) l++;
		else r--;
		flag^=1;
		if(ans[tot].size()>1){
			fun(tot);
			tot++;
		}
	}
	return tot;
}
int main(){
	scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	int tot=solve();
	printf("%d\n",tot);
	for(int i=0;i<tot;i++){
		printf("%d",ans[i].size());
		for(auto j:ans[i]) printf(" %d",j);
		printf("\n");
	}
	return 0;
}
 类似资料: