CF1276E

题目大意

4个相同石头在坐标轴的整点上,每次选定两个石头把一个根据另一个对称(x-->2y-x),求一种方案使得石头被移到给定位置

判断无解或用<=1000步完成

题解

神仙构造题

特判掉a全部相等的情况,设g=gcd(ai-a0),则ab中都应该根据g同余,否则显然不能跳

设余数为d,更进一步发现(a-d)/g中的奇数/偶数个数即等于(b-d)/g中的奇数/偶数个数,因为一次跳不能改变奇偶

然后把a和b变成(a/b-d)/g,最后还原一下

考虑构造解,分两步进行:

①把a/b分别移到[x,x+1]和[y,y+1]

②把[x,x+1]移到[y,y+1]

最后把b的操作反过来即可,以下均假设a单调递增

第一部分:

设d=(a3-a0+2)/4,考虑每次把l减少1/4

假设a1或a2∈[a0+l,a3-l],那么显然可以把a0或a3折到中间

否则考虑用log次操作使得a0a3不变(或a3-a0更小)并且把a1a2移到中间

①若a1a2分别在两侧,则选择靠两边距离较小(另一边必然大于0)的那个进行操作

假设是a1,那么就把a1先按a2翻转,再按a3翻转,结果会变成a0+2(a3-a2)

对两边轮流做,次数是log的(其实是斐波那契数)

②若a1a2在同一侧,则每次把a0/a3按照a2/a1翻转,次数也是log的

第二部分:

设当前a3-a0=l,那么可以通过整体翻转来移动l的长度

定义扩展操作,即把a2按a0翻转,a1按a3翻转,这样长度至少*2

所以扩展到一次不超过距离的最大长度即可,之后不断还原回去同时逼近[y,y+1]即可

总次数也是log的,注意最后的l要为1

code

挂了10发

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
//#define file
using namespace std;

struct Ans{
	ll a[1001][2];
	int tot;
	void add(ll x,ll y) {if (x==y) return;++tot;a[tot][0]=x;a[tot][1]=y;}
} A,B;
ll a[4],b[4],d,g;
int i,j,k,l;

ll gcd(ll x,ll y) {ll r=x%y; while (r) x=y,y=r,r=x%y; return y;}
ll turn(ll t) {return t*g+d;}

void Turn(ll *a) {fo(i,0,3) a[i]=(a[i]-d)/g;}
void jump(ll &x,ll &y) {x=y*2-x;}

void work(ll *a,Ans &b)
{
	ll d;
	while (a[3]-a[0]>1)
	{
		d=(a[3]-a[0]+2)/4;
		if (a[0]+d<=a[1] && a[1]<=a[3]-d)
		{
			if (a[1]*2-a[0]<=a[3])
			b.add(a[0],a[1]),jump(a[0],a[1]);
			else
			b.add(a[3],a[1]),jump(a[3],a[1]);
		}
		else
		if (a[0]+d<=a[2] && a[2]<=a[3]-d)
		{
			if (a[2]*2-a[0]<=a[3])
			b.add(a[0],a[2]),jump(a[0],a[2]);
			else
			b.add(a[3],a[2]),jump(a[3],a[2]);
		}
		else
		{
			while (!(a[0]+d<=a[1] && a[1]<=a[3]-d) && !(a[0]+d<=a[2] && a[2]<=a[3]-d))
			{
				if (a[1]<a[0]+d && a[3]-d<a[2])
				{
					if (a[1]-a[0]<a[3]-a[2])
					b.add(a[1],a[2]),jump(a[1],a[2]),b.add(a[1],a[3]),jump(a[1],a[3]);
					else
					b.add(a[2],a[1]),jump(a[2],a[1]),b.add(a[2],a[0]),jump(a[2],a[0]);
				}
				else
				if (a[3]-d<a[1])
				b.add(a[3],a[1]),jump(a[3],a[1]);
				else
				b.add(a[0],a[2]),jump(a[0],a[2]);
				sort(a,a+4);
			}
		}
		sort(a,a+4);
	}
}

void kuo()
{
	A.add(a[2],a[0]),jump(a[2],a[0]);
	A.add(a[1],a[3]),jump(a[1],a[3]);
	sort(a,a+4);
}
void suo()
{
	A.add(a[0],a[1]),jump(a[0],a[1]);
	A.add(a[3],a[2]),jump(a[3],a[2]);
	sort(a,a+4);
}
void Work()
{
	ll d,l;
	if (a[3]<=b[0])
	{
		while (!(a[3]-a[0]==1 && a[0]==b[0]))
		{
			d=b[3]-a[3],l=a[3]-a[0];
			if (l>=d)
			{
				while (l>max(d,b[3]-b[0])) suo(),d=b[3]-a[3],l=a[3]-a[0];
				if (a[0]!=b[0] || a[3]!=b[3])
				fo(i,0,2) A.add(a[i],a[3]),jump(a[i],a[3]);
			}
			else
			{while (l<d) kuo(),d=b[3]-a[3],l=a[3]-a[0];}
			sort(a,a+4);
		}
	}
	else
	if (b[3]<=a[0])
	{
		while (!(a[3]-a[0]==1 && a[0]==b[0]))
		{
			d=a[0]-b[0],l=a[3]-a[0];
			if (l>=d)
			{
				while (l>max(d,b[3]-b[0])) suo(),d=a[0]-b[0],l=a[3]-a[0];
				if (a[0]!=b[0] || a[3]!=b[3])
				fd(i,3,1) A.add(a[i],a[0]),jump(a[i],a[0]);
			}
			else
			{while (l<d) kuo(),d=a[0]-b[0],l=a[3]-a[0];}
			sort(a,a+4);
		}
	}
}

int main()
{
	#ifdef file
	freopen("CF1276E.in","r",stdin);
	#endif
	
	fo(i,0,3) scanf("%lld",&a[i]);sort(a,a+4);
	fo(i,0,3) scanf("%lld",&b[i]);sort(b,b+4);
	if (a[3]==a[0] || b[3]==b[0])
	{
		if (a[3]==a[0] && b[3]==b[0] && b[0]==a[0]) printf("0
"); else printf("-1
");
		return 0;
	}
	
	g=a[3]-a[0];
	fo(i,1,2) if (a[i]>a[0]) g=gcd(g,a[i]-a[0]);
	d=((a[0]%g)+g)%g;
	
	Turn(a);
	l=b[3]-b[0];
	fo(i,1,2) if (b[i]>b[0]) l=gcd(l,b[i]-b[0]); if (l!=g) {printf("-1
");return 0;}
	fo(i,0,3)
	if ((b[i]%g+g)%g!=d) {printf("-1
");return 0;}
	Turn(b);
	k=l=0;
	fo(i,0,3) if (a[i]&1) ++k; else ++l;
	fo(i,0,3) if (b[i]&1) --k; else --l;
	if (k && l) {printf("-1
");return 0;}
	
	work(a,A),work(b,B);
	Work();
	
	printf("%d
",A.tot+B.tot);
	fo(i,1,A.tot) printf("%I64d %I64d
",turn(A.a[i][0]),turn(A.a[i][1]));
	fd(i,B.tot,1) printf("%I64d %I64d
",turn(B.a[i][1]*2-B.a[i][0]),turn(B.a[i][1]));
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
原文地址:https://www.cnblogs.com/gmh77/p/13340830.html