HDU 5524:Subtrees

Subtrees

 
 Accepts: 60
 
 Submissions: 170
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 131072/131072 K (Java/Others)
问题描述
一棵有N个节点的完全二叉树,问有多少种子树所包含的节点数量不同。
输入描述
输入有多组数据,不超过1000组.
每组数据输入一行包含一个整数N.(1\leq N\leq {10}^{18})(1N1018)
输出描述
对于每组数据输出一行,表示不同节点数的子树有多少种.
输入样例
5
6
7
8
输出样例
3
4
3
5

一颗完全二叉树,左右子树都会为完全二叉树,其中必然有一个最后一层是满的。对于最后一层是满的完全二叉树,每一层的节点的子树形态都是相同的,只统计logN种,然后递归处理另一颗子树。最后对记录下的所有子树根据节点数判重.

这道题想了很久,果然递归真的是省事啊。。。

网上的题解完全看不懂什么意思,之前也一直不敢写递归,总怕出错。这次敲完爽翻了。我真是太弱了。。。这道题兴奋半天。。。

具体解释见代码:

#pragma warning(disable:4996)  
#include <iostream>  
#include <algorithm>  
#include <cmath>  
#include <vector>  
#include <string>  
#include <cstring>
#include <set>
using namespace std;

typedef long long ll;

ll n;
set<ll>an;

void solve(ll x)
{
	if (x <= 0)
		return;
	if (x == 1)
	{
		an.insert(0);
		return;
	}
	int i;
	ll num, k, nn, nk;
	for (i = 0; i <= 60; i++)
	{
		num = (1LL << i);
		if ((num - 1) == x)//中奖了,是满二叉树(其实早晚会中奖......)
		{
			k = 0;
			nn = 2;
			while (k + 1 <= x)
			{
				an.insert(k);
				k = k + nn;
				nn = nn << 1;
			}
			return;
		}
		if (num >= x)
		{
			break;
		}
	}
	an.insert(x - 1);
	i--;
	nn = (1LL << i) - 1;//除去最后一层的节点数
	k = x - nn;//最后一层的节点数

	nk = ((1LL << i) >> 1);//最后一层应该有的一半节点数
	ll temp = (nn - 1) >> 1;
	ll le, ri;
	if (k <= nk)
	{
		le = temp + k;//搜索左子树节点
		ri = temp;//搜索右子树节点
	}
	else
	{
		le = temp + nk;
		ri = temp + k - nk;
	}
	solve(le);
	solve(ri);
}

int main()
{
	//freopen("i.txt", "r", stdin);
	//freopen("o.txt", "w", stdout);

	while (cin >> n)
	{
		an.clear();
		solve(n);
		cout << an.size() << endl;
	}
	//system("pause");
	return 0;
}

posted on 2015-11-16 20:50  光速小子  阅读(226)  评论(0编辑  收藏  举报

导航