题目
Input
Sample Input
1 2 3
0 3 5
Output
Sample Output
YES
2
Data Constraint
题目大意
现在有A,B,C三个点,位置分别在x,y,z每一次我们可以进行下列的一项操作,将位置变为:
1:(x,x-(y-x),z)
2:(x,z+(z-y),z)
3:(y+(y-x),y,z)并且此时新的x位置要在z的前面,否则不能这样动
4:(x,y,z-(y-x))并且此时新的位置要在x的后面,否则不能这样动
现在给出初始位置和目标位置,求所需要的最短的步数(不一定要到对应的位置,只要xyz都到了三个目标位置的其中一个就可以了)
比赛时の想法
好难啊(╯‵□′)╯只会暴力
正解
这一题可以转化成一个树的模型并且求解,我们可以发现上面3,4两种转换方式只有一种是可行的,那么不妨把这种转换设为当前状态的父亲,同理,1,2两种状态设为当前状态的儿子。我们可以发现,对于任意一个三元组(x,y,z(x<y<z)),如果一直进行3,4操作,那么到最后一定会两种操作都进行不了(y-x=z-y)我们可以把这个状态设为这个三元组所在树的树根。当起始三元组和目标三元组到根都不相等时,那么这两个三元组就不在一棵树上,也就不可能转换为彼此了。
我们可以先把两个三元组都往根跑一遍,顺便得出深度,然后再二分一下,就可以得出两个三元组相交时的深度了,这个方法可以拿40分(居然才给40分QAQ)
我们发现,上面的方法时间主要损耗在往根跑的时候,举个例子(1,2,10000000)这种情况要跳很多次,而且没有意义,为了解决这个问题,我们设t1=y-x,t2=z-y;当t1<t2时显然可以往右边跳(t2-1)/t1(下取整)次,当t1>t2时也是一样的,那么我们就可以一次可以跳很多步了。(注意不能跳到二分深度的上面去了,要判断一下)
贴代码
一堆注释2333
const n=3;
var
a,b,c:array[0..5]of longint;
i,j,k,l,r,x,y,z,deep1,deep2,mid:longint;
bz:boolean;
function min(x,y:longint):longint;
begin
if x<y then exit(x) else exit(y);
end;
function max(x,y:longint):longint;
begin
if x>y then exit(x) else exit(y);
end;
procedure work1(p:longint);
var
i,j,k,l,r:longint;
begin
l:=y-x;
r:=z-y;
if l=r then exit;
if l<r then
begin
k:=(r-1) div l;
if p-k<mid then k:=p-mid;
p:=p-k;
//if k>p then k:=p;
//p:=p-k;
x:=x+k*l;
y:=y+k*l;
if bz=false then
deep1:=deep1+k;
end else
begin
k:=(l-1) div r;
if p-k<mid then k:=p-mid;
p:=p-k;
//if k>p then k:=p;
//p:=p-k;
y:=y-k*r;
z:=z-k*r;
if bz=false then
deep1:=deep1+k;
end;
if p>mid then work1(p);
end;
procedure work2(p:longint);
var
i,j,k,l,r:longint;
begin
l:=y-x;
r:=z-y;
if l=r then exit;
if l<r then
begin
k:=(r-1) div l;
if p-k<mid then k:=p-mid;
p:=p-k;
//if k>p then k:=p;
//p:=p-k;
x:=x+k*l;
y:=y+k*l;
if bz=false then
deep2:=deep2+k;
end else
begin
k:=(l-1) div r;
if p-k<mid then k:=p-mid;
p:=p-k;
//if k>p then k:=p;
//p:=p-k;
y:=y-k*r;
z:=z-k*r;
if bz=false then
deep2:=deep2+k;
end;
if p>mid then work2(p);
end;
procedure init;
begin
for i:=1 to n do read(a[i]);
for i:=1 to n-1 do
for j:=i+1 to n do
if a[i]>a[j] then
begin
a[0]:=a[i];
a[i]:=a[j];
a[j]:=a[0];
end;
for i:=1 to n do read(b[i]);
for i:=1 to n-1 do
for j:=i+1 to n do
if b[i]>b[j] then
begin
b[0]:=b[i];
b[i]:=b[j];
b[j]:=b[0];
end;
x:=a[1]; y:=a[2]; z:=a[3];
work1(maxlongint);
c[1]:=x; c[2]:=y; c[3]:=z;
x:=b[1]; y:=b[2]; z:=b[3];
work2(maxlongint);
if (c[1]<>x) or (c[2]<>y) or (c[3]<>z) then
begin
writeln('NO');
halt;
end;
writeln('YES');
l:=0;
//if deep1=0 then deep1:=1;
//if deep2=0 then deep2:=1;
//dec(deep1); dec(deep2);
r:=min(deep1,deep2);
bz:=true;
end;
begin
init;
while l<r do
begin
mid:=(l+r) div 2;
x:=a[1]; y:=a[2]; z:=a[3];
work1(deep1);
c[1]:=x; c[2]:=y; c[3]:=z;
x:=b[1]; y:=b[2]; z:=b[3];
work2(deep2);
if (c[1]=x) and (c[2]=y) and (c[3]=z) then l:=mid+1 else r:=mid;
end;
//l:=min(deep1,deep2)-l;
//l:=mid;
r:=mid;
mid:=max(l,mid);
x:=a[1]; y:=a[2]; z:=a[3];
work1(deep1);
c[1]:=x; c[2]:=y; c[3]:=z;
x:=b[1]; y:=b[2]; z:=b[3];
work2(deep2);
if (c[1]=x) and (c[2]=y) and (c[3]=z) then l:=mid else l:=mid-1;
writeln(abs(l-deep1)+abs(l-deep2));
end.