题目大意
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;
}