Description
Solution
我们可以设三个人所在位置为一个三元组(x,y,z),转移状态分为左右两边的向中间跳、中间向两边跳三种,因为两边向中间跳只会推导出一种状态,所以把两边向中间跳作为当前状态的父亲,把所有状态转化成树之后,所求就是起始状态与目标状态的lca,与两个状态的深度差之和,如果没有交集则无解。
设 l = y-x, r = z-y,
1. 中间向两边跳 S(x, y, z) - S(x-l, y-l, z), S(x, y, z) - S(x, y-r, z-r)
2. 两边向中间跳
当l< r,S(x,y,z)-S(x+l,y+l,z)。
当r> l,S(x,y,z)-S(x,y-r,z-r).
由于状态深度可能会很大,所以一步步跳可能会很慢。仔细观察发现,这个状态转移有些像辗转相除法,即更相减损术,一次能够跳多步,时间上快很多。
Code
type
arr=array[0..3] of longint;
var
a,b,s,s1,s2:arr;
i,j,d1,d2,ans,ll,rr,mid:longint;
bz:boolean;
procedure px(var x:arr);
begin
for i:=1 to 2 do
for j:=i+1 to 3 do
if x[i]>x[j] then begin x[0]:=x[i];x[i]:=x[j];x[j]:=x[0]; end;
end;
procedure cz(sum,x,y:longint;var s:arr);
begin
s[x]:=s[x]+sum;s[y]:=s[y]+sum;
end;
function min(x,y:longint):longint;
begin
if x<y then exit(x) else exit(y);
end;
function ask(deep:longint;var x:arr):longint;
var l,r:longint;
begin
px(x);
l:=x[2]-x[1];r:=x[3]-x[2];
if deep=0 then exit;
if (l=r)or(x[1]=x[2])or(x[2]=x[3])or(x[1]=x[3]) then exit(0);
if l<r then cz(min(deep,(r-1)div l)*l,1,2,x)
else cz(-min(deep,(l-1)div r)*r,2,3,x);
if l<r then exit(ask(deep-min(deep,(r-1)div l),x)+(r-1)div l)
else exit(ask(deep-min(deep,(l-1)div r),x)+(l-1)div r);
end;
function pd(a,b:arr):boolean;
var i:longint;
begin
for i:=1 to 3 do
if a[i]<>b[i] then exit(false);
exit(true);
end;
begin
for i:=1 to 3 do read(a[i]);
for i:=1 to 3 do read(b[i]);
px(a);
px(b);
s1:=a;s2:=b;
d1:=ask(maxlongint,s1);
d2:=ask(maxlongint,s2);
if pd(s1,s2)=false then
begin
writeln('NO');
exit;
end;
writeln('YES');
ans:=0;
ll:=0;rr:=min(d1,d2);
while ll<rr do
begin
mid:=(ll+rr)div 2;
s1:=a;s2:=b;
ask(d1-mid,s1); ask(d2-mid,s2);
if pd(s1,s2) then
begin
ans:=mid;
ll:=mid+1;
end
else rr:=mid-1;
end;
s1:=a;s2:=b;
ask(d1-ll,s1); ask(d2-ll,s2);
if pd(s1,s2) then ans:=ll;
ans:=d1-ans+d2-ans;
writeln(ans);
end.