UVA679 小球下落 Dropping Balls【題解】
阿新 • • 發佈:2019-01-07
題意
許多的小球一個一個的從一棵滿二叉樹上掉下來組成一個新滿二叉樹,每一時間,一個正在下降的球第一個訪問的是非葉子節點。然後繼續下降時,或者走右子樹,或者走左子樹,直到訪問到葉子節點。
決定球運動方向的是每個節點的布林值。最初,所有的節點都是
,當訪問到一個節點時,如果這個節點是
,則這個球把它變成
,然後從左子樹走,繼續它的旅程。如果節點是
,則球也會改變它為
,而接下來從右子樹走。滿二叉樹的標記方法如下圖。
因為所有的節點最初為
,所以第一個球將會訪問節點
,節點
和節點
,轉變節點的布林值後在在節點
停止。第二個球將會訪問節點
、
、
,在節點
停止。明顯地,第三個球在它停止之前,會訪問節點
、
、
,在節點 10 停止。
現在你的任務是,給定新滿二叉樹的深度
和下落的小球的編號
,可以假定I不超過給定的新滿二叉樹的葉子數,寫一個程式求小球停止時的葉子序號
。
此題直接模擬會超時
所以我們想一下更快的做法 :
模擬一下下落的過程,當第 個小球下落時,若 為奇數,則落到左子樹中,若 為偶數,則落到右子樹中
到第二層時,若 為奇數,則落到它的左子樹中,反之落到右子樹中…
這樣一步一步模擬,就將複雜度由 變為 ,是完全可過的。
程式碼奉上:
#include<iostream>
#include<cstdio>
#include<ctype.h>
using namespace std;
inline int read(){
int x=0,f=0;char ch=getchar();
while(!isdigit(ch))f|=ch=='-',ch=getchar();
while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
return f?-x:x;
}
int main(){
int n=read();
while(n--){
int deep=read(),i=read(),p=1;
while(--deep){
p<<=1;
if(i%2)i=i+1>>1;
else i>>=1,++p;
}
printf("%d\n",p);
}
return 0;
}