列表

详情


NC231614. Swap!Swap!Swap!Swap!Swap!

描述

作为一个即将开始考研的废物点心,Murphy在退役之后已经着手准备了!

为了考上梦想的**枝江大学**,Murphy已经制定了未来的考研计划,他在每一张纸上都写下他第几天该做些什么,一共写下了n张纸(n是一个偶数),每一张纸都有一个编号i,编号表示第i天的计划,刚开始所有计划的编号都是升序的。Murphy觉得只要按照顺序完成写下的计划,就能成为一名Master

可是嗷子总想带着Murphy找准进厂时机,于是嗷子将Murphy的计划全部打乱,并且对Murphy说:Miu子啊,我们一起进厂吧。Murphy不想理会嗷子,只想快点整理好自己的考研计划开始预习...


嗷子看到Murphy心中如此坚定,于是便开始拷打他,如果Murphy能够满足嗷子的条件,Murphy便可以继续考研。


Murphy每次可以将两张考研计划进行交换,倘若每次交换的考研计划在当前计划序列中的**位置(注意是计划的当前位置,不是计划的编号)**,满足,则Murphy可以不付出任何代价;否则Murphy需要付出1的代价。

嗷子需要Murphy用最小的代价让他自己的考研计划的编号序列,恢复成为初始的样子,即恢复成升序。

输入描述

第一行包含一个整数n,为Murphyn张考研计划。

第二行包含n个数,表示打乱后计划编号序列。a_i为打乱后在位置i的考研计划的编号,

输出描述

第一行包含一个整数cost,表示将考研计划编号变为升序的最小花费。

第二行包换一个整数num,表示你需要进行交换的操作次数。

接下来num行包含两个整数l,r,表示交换位置为l,r的两个计划,即交换

示例1

输入:

6
5 6 4 2 1 3

输出:

0
10
1 5
2 6
1 4
1 6
2 6
1 4
3 6
6 1
4 1
6 1

说明:

Hint:注意输入输出对时限的影响,建议用scanf和printf输入输出

对于样例1

第5天的计划在位置1,第6天的计划在位置2...第3天的计划在位置6。

交换位置为1和5的计划,计划序列变为1 6 4 2 5 3

交换位置为2和6的计划,计划序列变为1 3 4 2 5 6

交换位置为1和4的计划,计划序列变为2 3 4 1 5 6

交换位置为1和6的计划,计划序列变为6 3 4 1 5 2

交换位置为2和6的计划,计划序列变为6 2 4 1 5 3

交换位置为1和4的计划,计划序列变为1 2 4 6 5 3

...

此样例每一次交换都不需要符出代价。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 254ms, 内存消耗: 20104K, 提交时间: 2023-02-23 14:14:37

#include<bits/stdc++.h>
using namespace std;
int l[3000000],r[3000000],a[1000000];
int main()
{
 	int t=1;
 	while (t--)
 	{
 		int n;
 		scanf("%d",&n);
 		for (int i=1;i<=n;i++) scanf("%d",&a[i]);
 		int len=0,ret=0;
 		for (int i=1;i<=n;)
 		{
 			//printf("%d %d\n",i,a[i]);
 			if (a[i]==i) 
			{
				i++;
			 	continue;
			}
			int tmp;
			if (i<=n/2) tmp=n;
			else tmp=1;
			if (abs(a[i]-i)>=n/2)
			{ 
				int xx=a[i]; 
				len++;
				l[len]=i,r[len]=a[i];
				swap(a[i],a[xx]);
			}
			else
			{
				//printf("%d %d %d\n",i,a[i],tmp);
				if (abs(a[i]-tmp)<n/2) 
				{
					int nex,xx=a[i];
					//printf("why %d %d\n",i,a[i]);
					if (tmp==1) nex=n;
					else nex=1;
					if (i==1) nex=2;
					len++;l[len]=i,r[len]=tmp;
					swap(a[i],a[tmp]);
					len++;l[len]=tmp,r[len]=nex;
					swap(a[tmp],a[nex]);
					len++;l[len]=nex,r[len]=xx;
					swap(a[nex],a[xx]);
					len++;l[len]=tmp,r[len]=nex;
					swap(a[tmp],a[nex]);
					len++;l[len]=i,r[len]=tmp;
					swap(a[i],a[tmp]);
				}	
				else
				{
					int xx=a[i];
					len++; l[len]=i,r[len]=tmp;
					swap(a[i],a[tmp]);
					len++; l[len]=tmp,r[len]=xx;
					swap(a[tmp],a[xx]);
					len++; l[len]=tmp,r[len]=i;
					swap(a[tmp],a[i]);
				}
			}
			//for (int i=1;i<=n;i++) printf("%d ",a[i]);
			//printf("\n");
			//if (len>100) break;
		}
		printf("0\n%d\n",len);
		for (int i=1;i<=len;i++) printf("%d %d\n",l[i],r[i]);
 	}
 	return 0;
}

C++ 解法, 执行用时: 173ms, 内存消耗: 26412K, 提交时间: 2021-12-12 13:05:24

#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int n,m,i,j,k,x,y,t,ans[3*N],cnt,a[N],b[N],ans2[3*N];
void doit(int x,int y){if (x==y) return;
	t=a[x];a[x]=a[y];a[y]=t;b[a[x]]=x;b[a[y]]=y;ans[++cnt]=x;ans2[cnt]=y;
}
int main(){
	scanf("%d",&n);for (i=1;i<=n;i++) scanf("%d",&a[i]),b[a[i]]=i;printf("0\n");
	for (i=0;i<=n/2-1;i++){
		if (n/2-i!=a[n/2-i]){
			if (b[n/2-i]>n/2) doit(1,b[n/2-i]);
			doit(b[n/2-i],n),doit(n,n/2-i);
		}
		if (n/2+i+1!=a[n/2+i+1]){
			if (b[n/2+i+1]<=n/2) doit(b[n/2+i+1],n);
			doit(b[n/2+i+1],1);doit(1,n/2+i+1);
		}
	}
	printf("%d\n",cnt);for (i=1;i<=cnt;i++) printf("%d %d\n",ans[i],ans2[i]);return 0;
}

上一题