如果发现广告等破坏行为,请尽量将条目恢复到较早的版本而不是把相应内容直接删除,谢谢合作。
URAL/1088
来自"NOCOW"
< URAL
#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.