题目链接
A number of K balls are dropped one by one from the root of a fully binary tree structure FBT. Each time the ball being dropped first visits a non-terminal node. It then keeps moving down, either follows the path of the left subtree, or follows the path of the right subtree, until it stops at one of the leaf nodes of FBT. To determine a ball’s moving direction a flag is set up in every non-terminal node with two values, either false or true. Initially, all of the flags are false. When visiting a non-terminal node if the flag’s current value at this node is false, then the ball will first switch this flag’s value, i.e., from the false to the true, and then follow the left subtree of this node to keep moving down. Otherwise, it will also switch this flag’s value, i.e., from the true to the false, but will follow the right subtree of this node to keep moving down. Furthermore, all nodes of FBT are sequentially numbered, starting at 1 with nodes on depth 1, and then those on depth 2, and so on. Nodes on any depth are numbered from left to right. For example, Fig. 1 represents a fully binary tree of maximum depth 4 with the node numbers 1, 2, 3, …, 15. Since all of the flags are initially set to be false, the first ball being dropped will switch flag’s values at node 1, node 2, and node 4 before it finally stops at position 8. The second ball being dropped will switch flag’s values at node 1, node 3, and node 6, and stop at position 12. Obviously, the third ball being dropped will switch flag’s values at node 1, node 2, and node 5 before it stops at position 10. Now consider a number of test cases where two values will be given for each test. The first value is D, the maximum depth of FBT, and the second one is I, the I-th ball being dropped. You may assume
the value of I will not exceed the total number of leaf nodes for the given FBT.
Please write a program to determine the stop position P for each test case.
For each test cases the range of two parameters D and I is as below: 2 ≤ D ≤ 20, and 1 ≤ I ≤ 524288.
Input
Contains l + 2 lines.
Line 1 l the number of test cases
Line 2 D1 I1 test case #1, two decimal numbers that are separated by one blank
…
Line k + 1 Dk Ik test case #k
Line l + 1 Dl Il test case #l
Line l + 2 -1 a constant ‘-1’ representing the end of the input file
Output
Contains l lines.
Line 1 the stop position P for the test case #1
…
Line k the stop position P for the test case #k
…
Line l the stop position P for the test case #l
1.刚开始模拟了一下两个深度分别为3和4的样例,然后就发现在第i层中,首先落下的2i-2次都是偶数且这2i-2中按奇偶数来分正好是把左一半右一半的偶数叶子节点逐一遍历,同理接下来的2i-2次都是奇数。然后直接写了一个规律的模拟,过了样例,交——WA。又读了一遍题,发现小球数目是任意的,而我刚开始按最多2i-1次个小球来考虑了
2.读了几遍标答,手动模拟,搞懂了。以前做过开关灯的问题,和这个确实有思想上的类似的,可以对比着想
3.想去看下大神们有没有什么更好的理解,确实有。某博客:第i个球走的路径是i-1二进制数的逆序。0代表左子树,1代表右子树。并由右向左走D-1次即可
4.大概想了一下上面的方法,果然是很神奇的规律,我们发现从0开始递增的数,对应二进制从右向左看,第一位的0、1交替周期是2,第二位的周期为4,第三位的周期为8…而且每一位都是从0开始,刚好和二叉树的每一层开关的交替周期相同!故在这个题中将0代表左子树,1代表右子树的话,刚好是依次取D-1的每一位,直到判断到最终的叶子节点上
标答:
#include <iostream>
using namespace std;
int main(){
int T,d,I;
while(scanf("%d",&T)!=EOF){
if(T==-1) break;
while(T--){
scanf("%d%d",&d,&I);
int ans=1;
for(int i=0;i<d-1;i++){ ///写位运算可大大节省时间
if(I&1){
ans<<=1;
I=(I+1)>>1;
}else{
ans=(ans<<1)+1;
I>>=1;
}
}
printf("%d\n",ans);
}
}
return 0;
}
神奇的规律:
#include <cstdio>
#include <iostream>
using namespace std;
int main(){
int T,p,q;
while(scanf("%d",&T)!=EOF){
if(T==-1) break;
while(T--){
scanf("%d%d",&p,&q);
int x=q-1;
int ans=1;
while(--p){
if(x&1){ ///判断最后一位是否为1,也可当做奇数偶数的判断
ans=(ans<<1)+1;
}else ans<<=1;
x>>=1;
}
printf("%d\n",ans);
}
}
return 0;
}