如果发现广告等破坏行为,请尽量将条目恢复到较早的版本而不是把相应内容直接删除,谢谢合作。

URAL/1088

来自"NOCOW"

跳转到: 导航, 搜索
#include <cstdio>
#include <cstring>
#include <iostream>
 
using namespace std;
int D, E, F, Dp, Ep, H;
int D_a[31], E_a[31];
int main()
{
    cin >> D >> E >> F >> Dp >> Ep >> H;
    Dp --;
    Ep --;
 
    for (int i = 0; i <= F; ++i)
        if (i >= D && i >= E && ((Dp >> i) << i) == ((Ep >> i) << i) )
        {
            puts( i * 2 - D - E <= H ? "YES" : "NO" );
            return 0;
        }
}

应该很容易看懂了, 毕竟不长

//纯粹用二叉树的知识做的,找找规律就是喽。但是最近公共祖先有待改进,那位大牛看到可以改一下。
 
Program U1088;//By Watercow101[http://hi.baidu.com/watercow101]
 
Const
  fin                   =       'U1088.in';
  twos                  :       Array [0..30] of Longint
                    	=       (1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824);
 
Var
  D,E,F,Dp,Ep,H         :       Longint;
  Alyosha,Llya          :       Longint;
  Lcf                   :       Longint;
 
Function GetWhere(Deep,son:Longint):Longint;
  var
    s,t,mid,x           :       Longint;
  begin
    s:=1;t:=twos[F-1];
    while s+twos[Deep]-1<>t do
      begin
        mid:=(s+t) shr 1;
        if (s<=son) and (son<=mid) then begin t:=mid;continue;end;
        s:=mid+1;
      end;
    x:=t Div twos[Deep];
    x:=twos[F-Deep]-1+x;
    Exit(x);
  end;
 
Procedure Init;
  var
    i                   :       Longint;
  begin
    readln(D,E,F,Dp,Ep,H);Inc(F);
    Alyosha:=GetWhere(D,Dp);
    Llya:=GetWhere(E,Ep);
  end;
 
Procedure GetLcf;
  var
    top,t,i             :       Longint;
    father              :       Array [1..100] of Longint;
  begin
    top:=1;t:=Alyosha shr 1;father[top]:=Alyosha;
    while True do
      begin
        if t=0 then break;
        inc(top);
        father[top]:=t;
        t:=t shr 1;
      end;
    t:=Llya;
    while True do
      begin
        if t=0 then break;
        for i:=1 to top do
          begin
            if father[i]=t then
              begin
                Lcf:=t;
                Exit;
              end;
            if father[i]<t then break;
          end;
        t:=t shr 1;
      end;
  end;
 
Procedure Main;
  begin
    GetLcf;
  end;
 
Procedure Print;
  var
    h_f,h_A,h_L         :       Longint;
    dis                 :       Longint;
  begin
    h_f:=trunc(ln(Lcf)/ln(2))+1;
    h_A:=trunc(ln(Alyosha)/ln(2))+1;
    h_L:=trunc(ln(Llya)/ln(2))+1;
    dis:=abs(h_f-h_A)+abs(h_f-h_L);
//    writeln(dis);
    if dis<=H
      then writeln('YES')
      else writeln('NO');
  end;
 
Begin
  Assign(INPUT,fin);Reset(INPUT);
  Init;
  Close(INPUT);
  Main;
  Print;
End.

我的方法是把二叉树的非叶子结点也标上号,从根节点开始1、2、3……标号,那么叶子结点依次就是2^F,2^F+1……2^(F+1)-1。 这样将它变成普通的满二叉树,计算公共结点时直接用完全二叉树的性质就可以了。

var a:array[0..50]of longint;
    d,e,f,h,dp,ep,l,l1,i:longint;
begin
   readln(d,e,f,dp,ep,h);dp:=(dp+1 shl f-1)shr d;ep:=(ep+1 shl f-1)shr e;
   l:=0;a[l]:=dp;while dp<>1 do begin l:=l+1;dp:=dp div 2;a[l]:=dp;end;l1:=0;
   repeat
      for i:=0 to l do if a[i]=ep then break;
      if a[i]=ep then begin if i+l1<=h then writeln('YES')else writeln('NO');break;end
      else begin l1:=l1+1;ep:=ep div 2;end;
   until false;
end.

——by SHUXK


自认为是最好的方法。 首先从寻找位置入手。建树,二叉树根节点为1,则叶节点为(2^F)-1+dp(或ep),为他们当前子树的叶节点,在这基础上 shr d(或e)为他们的节点。 然后是寻找最近公共祖先,因为是特殊二叉树,父亲的节点为儿子节点 shr 1,而从儿子爬到父亲必然要耗费1单位时间,那么只要判断当前哪个节点标号大,shr 1,顺便dec(h),就圆满完成任务。 程序清单:

program cyd;
  var
    p:array[0..31]of int64;
    i,j,k,l,m,n,a,b,c,f,e,dp,ep,h,d:longint;
  procedure print(s:string);
    begin
      writeln(s);
      halt;
    end;
  begin
    readln(d,e,f,dp,ep,h);
    p[0]:=1;
    for i:=1 to f do
      p[i]:=p[i-1]*2;
    dp:=(p[f]-1+dp) shr d;
    ep:=(p[f]-1+ep) shr e;
    while dp<>ep do
      begin
        dec(h);
        if h<0 then print('NO');
        if dp<ep then ep:=ep shr 1 else dp:=dp shr 1;
      end;
    print('YES');
  end.
个人工具