Codeforces Global Round 3 C. Crazy Diamond

链接

https://codeforces.com/problemset/problem/1148/C

题解

容易发现 1 1 1 n n n这两个位置是很好用的, 1 1 1可以和右半段中的任何一个交换, n n n可以和左半段中的一个任意交换
因此我构造的策略是,对于一个想换到左半段去的数字,我先想办法让它换到 n n n,然后再一步换到正确位置。
如果这个数字现在在左半段,那我就直接让它和 n n n交换;否则我可以让它先和 1 1 1交换再和 n n n交换

代码

#include
#define maxn 300010
#define linf (1ll<<60)
#define iinf 0x3f3f3f3f
#define eps 1e-8
#define cl(x) memset(x,0,sizeof(x))
#define mod 998244353ll
#define mp(a,b) make_pair(a,b)
using namespace std;
typedef long long ll;
ll read(ll x=0)
{
	int c, f=1;
	for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
	for(;isdigit(c);c=getchar())x=x*10+c-48;
	return f*x;
}
ll N, a[maxn], pos[maxn];
vector< pair<ll,ll> > ans;
void opt(ll x, ll y)
{
	ans.emplace_back(make_pair(x,y));
	swap(pos[a[x]],pos[a[y]]);
	swap(a[x],a[y]);
}
int main()
{
	N=read();
	ll i;
	for(i=1;i<=N;i++)
	{
		a[i]=read();
		pos[a[i]]=i;
	}
	for(i=2;i<=N/2;i++)
	{
		if(pos[i]<=N/2)
		{
			opt(pos[i],N);
			opt(N,i);
		}
		else
		{
			opt(pos[i],1);
			opt(1,N);
			opt(N,i);
		}	
	}
	for(;i<N;i++)
	{
		if(pos[i]<=N/2)
		{
			opt(pos[i],N);
			opt(N,1);
			opt(1,i);
		}
		else
		{
			opt(1,pos[i]);
			opt(1,i);
		}
		
	}
	if(a[1]!=1)opt(1,N);
	printf("%d\n",ans.size());
	for(auto p:ans)
	{
		printf("%lld %lld\n",p.first,p.second);
	}
	return 0;
}

你可能感兴趣的:(构造)