题目链接 : Dropping Balls
题目大意
第一句话告诉我们这是一个满二叉树,小球从树节点1开始往下掉落,每个树节点会有一个开关,开关初始全部关闭。当每次有小球落在上面时,开关的状态会发生改变。如果小球落到树节点时开关关闭则向左子树走,否则向右子树走。
现在问第i个小球下落到d层时,d层所经过的开关编号。
解题思路
读完题目,首先想到了直接开数组,按照顺序模拟,后来看到I的取值最大到524288,D最大到20,每组数据计算量最高可能到达524288*19=9961472接近1000万,而组数可以有多组。所以不难想到用这个方法应该会超时,所以寻找一下规律。
我们只需要知道小球是第几个落到该树节点的,便可知道小球往左子树还是往右子树。
不难发现,小球到达树节点时,奇数的时候往左子树走,偶数时候往右子树走。对于树节点n,其左子节点为2n, 右子节点为2n+1;
所以我们可以直接模拟第i个球路线,有i个球经过最初的树节点,如果i是奇数往左,偶数往右,然后就有i/2个球分别进入了下一个子树,子树又变成了树节点,然后判断i/2是奇数还是偶数,便可以知道小球往左还是往右,依此类推便可得到第i个球的路线。根据路线便可计算出开关编号。
复杂度分析
时间复杂度为O(n*d)
算法资料
一道思维题
心得体会
看到题目后可以先分析一下想出来的方法可行性,再写题目。
代码
#include <cstdio>
int main()
{
int n, d, i, ans;
while(scanf("%d", &n) != EOF && n != -1)
{
while(n--)
{
scanf("%d %d", &d, &i);
ans = 1;
for (int j = 1; j < d; j++)
{
if(i&1)
{
ans = ans*2;
i = (i+1)/2;
}
else
{
ans = ans*2+1;
i = i/2;
}
}
printf("%d\n", ans);
}
}
return 0;
}