bzoj 2144 二分&lca 神题详解

61 篇文章 0 订阅
13 篇文章 0 订阅

题目:跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。(棋子是没有区别的)跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。  写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。

一眼看上去多像usaco的抓住那只牛,然而这道题bfs只可以得20分...(我是蒟蒻我骄傲...= =)

好吧,我们来说正经的题解

对于局势(a,b,c),我们保证a<b<c,我们讨论可以到达的局势

(1)中间的b可以随意向两边跳 即 b跳到左边 ->(2a-b,a,c)或 b跳到右边 -> (a,c,2c-b)

(2)对于两边的a和c向中间跳,

         ①b-a = c-b a和c都不可跳

         ②b-a > c-b c可以往中间跳  -> (a,2b-c,b) 

         ③b-a < c-b a可以往中间跳 ->  (b,2b-a,c)

显然,对于每种局势(a,b,c)都对应两种向两边跳的局势,而最多有一种向中间跳的;同时,相对于向两边跳的,原局势即为它们往中间跳的唯一对应的局势

所以,我们令 往中间跳可以到达的局势(a',b',c')为原局势(a,b,c)的父亲节点向两边跳能到达的两种情况(a1,b1,c1)和 (a2,b2,c2)为 原局势(a,b,c)的子节点

那么,对于我们已知的局势(a,b,c),必然会形成一棵树,树上节点所代表的局势可互相到达

(其实这种思想和弹飞绵羊那道题很像)

如果我们的初始局势和最终局势不在同一棵树上,则必然不能完成转移,否则则可以到达

对于可以到达的情况,我们需要求出它最少的跳动次数

即求同一棵树上的两个节点间的距离,显然是lca,即求出各自到lca的距离累加即可,一般用lca或二分距离+判断即可

接下来我们需要解决的就是 如何在已知次数的情况下找到它所到达的局势 或者 在已知局势的情况的下找到转移的次数

显然后者就是我们题目所求,如果早就能解决它我们还在这里说这么一大堆做啥...

所以我们集中精力去解决第一个问题      “如何在已知次数的情况下找到它所到达的局势 ”

由于我们是求到lca的距离,所以我们只需要解决往中间跳即可

令 t1=b-a , t2=c-b 

   那么我们就可以用(t1,t2)来表示 局势(a,b,c)(所有的'/'表示下取整)

对于上面讨论的两边的a和c向中间跳的情况:

           ①t1=t2 a和c都不可跳,即当前局势为根节点

           ②t1>t2 c可以往中间跳 -> (t1-t2,t2),

             且最多跳 (t1-1)/t2 次直到c不能跳 -> (t1 % t2,t2) ,即(a,b - (t1-1)/t2 * t2,c - (t1-1)/t2 * t2)

             此时 (t1,t2)到(t1 % t2,t2)的深度(距离)为 (t1-1)/ t2

           ③t1<t2 a可以往中间跳 -> (t1,t2-t1),

              且最多跳 (t2-1)/t1 次直到a不能跳 ->(t1,t2 % t1), 即(a + (t2-1)/t1 *t1,b + (t2-1)/t1 * t1,c)

              此时  (t1,t2)到(t1,t2 % t1)的深度(距离)为 (t2-1)/ t1

类似碾转相除法的处理,我们可以在已知次数k的情况下,O(longk)找到所到达的局势

所以,对于上面所求同一棵树上两点间的距离,我们先把他们跳到同一深度,然后再二分到lca的距离,判断所到达局势是否相等即可

                                      最终答案=abs(d2-d1)+ tt*2 

  (d1、d2分别代表初始局势和最终局势到根的深度,tt表示二者跳到同一高度后到lca的距离)

注意:数据保证绝对值不超多10^9,所以一开始找初始局势和自重局势各自的根节点时,步数为10^9,mdzz一直少打个0,查了一个小时的错

type
        rec=array[0..3] of longint;
var
        a,b,t1,t2,t     :rec;
        i               :longint;
        n,l,d1,d2,r,mid :longint;
        ans,depth,tt    :longint;
function min(a,b:longint):longint;
begin
   if a<b then exit(a) else exit(b);
end;

procedure swap(var a,b:longint);
var
        c:longint;
begin
   c:=a; a:=b; b:=c;
end;

function check(a,b:rec):boolean;
var
        i:longint;
begin
   for i:=1 to 3 do
     if a[i]<>b[i] then exit(false);
   exit(true);
end;

procedure sort(var a:rec);
var
        i,j:longint;
begin
   for i:=1 to 3 do
     for j:=i+1 to 3 do
       if a[i]>a[j] then swap(a[i],a[j]);
end;

function find(a:rec;num:longint):rec;
var
        t1,t2,tt:longint;
        ans:rec;
begin
   t1:=a[2]-a[1]; t2:=a[3]-a[2];
   ans:=a;
   if t1=t2 then exit(ans);
   if t1<t2 then
   begin
      tt:=min(num,(t2-1) div t1);
      dec(num,tt); inc(depth,tt);
      inc(ans[2],tt*t1);
      inc(ans[1],tt*t1);
   end else
   begin
      tt:=min(num,(t1-1) div t2);
      dec(num,tt); inc(depth,tt);
      dec(ans[2],tt*t2);
      dec(ans[3],tt*t2);
   end;
   if num=0 then exit(ans) else exit(find(ans,num));
end;

begin
   for i:=1 to 3 do read(a[i]); sort(a);
   for i:=1 to 3 do read(b[i]); sort(b);
   t1:=find(a,1000000000); d1:=depth; depth:=0;
   t2:=find(b,1000000000); d2:=depth; depth:=0;
   if not check(t1,t2) then
   begin
      writeln('NO');exit;
   end else
   begin
      writeln('YES');
      if d1>d2 then
      begin
         swap(d1,d2);
         for i:=1 to 3 do swap(a[i],b[i]);
      end;
      ans:=d2-d1;
      t:=find(b,ans); b:=t;
      l:=0; r:=d1; mid:=0;
      while (l<=r) do
      begin
         mid:=(l+r)>>1;
         t1:=find(a,mid); depth:=0;
         t2:=find(b,mid); depth:=0;
         if check(t1,t2) then
         begin
            tt:=mid; r:=mid-1;
         end else l:=mid+1;
      end;
      inc(ans,tt*2);
      writeln(ans);
   end;
end.

——by Eirlys



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值