BC 61 Subtrees

本文探讨了如何计算给定大小的完全二叉树中不同节点数的子树数量,通过递推的方法解决此问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述
一棵有N个节点的完全二叉树,问有多少种子树所包含的节点数量不同。
输入描述
输入有多组数据,不超过1000组.
每组数据输入一行包含一个整数N.(1≤N≤1018)(1\leq N\leq {10}^{18})
输出描述
对于每组数据输出一行,表示不同节点数的子树有多少种.
输入样例
5
6
7
8
输出样例
3
4
3
5

这道题考到的是递推,因为是完全二叉树,所以总有一边的子树是满子树,而满子树的节点数不同的个数就是层数,所以可以每次去掉根节点,
然后减去满的那边,并将满子树的所有个数可能加进集合,统计个数就行了。

#include <stdio.h>
#include <set>
#define LL long long
const int maxn = 65;    //2^65才能超过10^18
LL sum[maxn];
int main ( )
{
    LL n;
    int ans;
    std :: set < LL > vis;
    sum[0] = 1;
    for ( int i = 1; i < maxn; i ++ )
        sum[i] = sum[i-1]*2;    //把2的次方保存到数组,用左移时间会超限
    while ( ~ scanf ( "%I64d", &n ) )
    {
        vis.clear ( );
        vis.insert ( n );
        ans = 1;
        n --;   //每次都去掉根节点
        while ( n > 0 )
        {
            int i;
            LL t = n;
            for ( i = 1; ; i ++ )
            {
                if ( t-sum[i] < 0 )
                    break ;
                t = t-sum[i];   //能搜到的最大层数
            }
            int m;
            if ( t >= sum[i-1] )    //大于等于上一层的一半时,往右
                m = i;
            else    //否则去掉右边部分,往左
                m = i-1;
            LL s = 0;
            for ( int j = 0; j < m; j ++ )
            {
                s = s+sum[j];   //统计删除层的每种个数
                if ( vis.count ( s ) )
                    continue ;
                ans ++;
                vis.insert ( s );
            }
            n = n-s;    //去掉一边子树
            if ( n && ! vis.count ( n ) )   //n!=0需要考虑
            {
                ans ++;
                vis.insert ( n );
            }
            n --;   //去掉根节点
        }
        printf ( "%d\n", ans );
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值