Throw

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.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值