【2015年奉化市】下落的小球(five.pas/c/cpp)

(File IO): input:five.in output:five.out

时间限制: 1000 ms 空间限制: 262144 KB 具体限制

题目描述

有一棵满二叉树,最大深度为D,且所有叶子的深度都相同。所有结点从上到下从左到右编号为1,2,3,…,2^D-1。在结点1处放一个小球,它会往下落。每个内结点上都有一个开关,初始全部关闭,当每次有小球落到一个开关上时,它的状态都会改变。当小球到达一个内结点时,如果该结点上的开关关闭,则往左走,否者往右走,直到走到叶子结点。
一些小球从结点1处依次开始下落,最后一个小球将会落到哪里呢?

输入

输入文件five.in
只有一行共有二个正整数:d k   (其中d为叶子深度,k为小球个数,1 <= k <= 2^(d-1) )

输出

输出文件five.out
只有一行且只有一个正整数:第k个小球最后所在的叶子编号

样例输入

16 12345

样例输出

36358

数据范围限制

50% 的数据: 1 <= d <= 40  
80% 的数据: 1 <= d <= 60  
100% 的数据: 1 <= d <= 100 

提示(二叉树知识拓展)

思路: 这道题其实也不算难,只是高精度乘除分。
首先,我们了解一下上面那个链接,然后再推一下满二叉树的特性

1)叶子只能出现在最下一层。出现在其它层就不可能达成平衡。

2)非叶子结点的度一定是2,即他们的下一层都有两个结点。

3)在同样深度的二叉树中,满二叉树的结点个数最多,叶子数最多。

4)对于除却根结点的任意结点,父亲结点都为i/2,左子树为2i,右子树为2i+1。(重点)

对于每一个球,我们都能推出他应该向左还是向右,所以利用4),我们就能得到其最后球最后在哪个结点。

代码:

#include<bits/stdc++.h>
using namespace std;
long long d,k[10005],a[10005],js=1;
char f;
int main(){
	freopen("five.in","r",stdin);
	freopen("five.out","w",stdout);
	scanf("%d",&d);
	cin>>f;
	while(f>='0'&&f<='9'){
		k[0]+=1;
		k[k[0]]=f-'0';
		f=getchar();
	}
	a[0]=1;
	a[1]=1;
	for(int i=1;i<d;i++){
		for(int j=1;j<=a[0];j++){
			a[j]*=2;
		}
		for(int j=1;j<=a[0]+1;j++){
			a[j+1]+=a[j]/10;
			a[j]=a[j]%10;
		}
		if(k[k[0]]%2==0){
			a[1]++;
			for(int j=1;j<=a[0];j++){
				a[j+1]+=a[j]/10;
				a[j]=a[j]%10;
			}
		}
		if(a[a[0]+1]!=0){
			a[0]++;
		}
		int bj=0;
		if(k[k[0]]%2==1) k[k[0]]+=1;
		for(int j=js;j<=k[0];j++){
			k[j+1]+=k[j]%2*10;
			if(k[j]/2!=0||bj==1){
				k[j]=k[j]/2;
				bj=1;
			}
			else if(bj==0) js++;;
		}
	}
	for(int i=a[0];i>=1;i--){
		printf("%d",a[i]);
	}
	fclose(stdin);
	fclose(stdout);
	return 0;
}

写博不易,请发现问题的大佬提出。

代码保证正确,请留赞再走。

原文地址:https://www.cnblogs.com/2020-zhy-jzoj/p/13159908.html