AtCoder "NOMURA Programming Competition 2020" C


NOMURA Programming Competition 2020 - C - Folia


题意

给定 N 和 N+1 个整数 A0 A1 ... AN

问是否存在一棵二叉树,最大深度为 N

且深度为 i 的叶子节点有 Ai

如果存在,输出二叉树最大可能的节点数

不存在,输出 -1


限制

Time Limit: 2 sec

Memory Limit: 1024 MB

  • 0≤N≤105
  • 0≤Ai≤108 (0≤i≤N)
  • AN≥1



解题思路

因为要求的是最大可能的节点数

在叶子节点数量固定的情况下

每个叶子节点必须有个父节点(根节点除外),且每个节点最多有两个子节点

所以最好能够多出现叶子节点的父节点只有一个子节点的情况

所以先求出 SUM{Ai , 0≤i≤N} ,代表这颗二叉树的叶子节点数量


假设在第 i-1 层,非叶子节点有 n 个,从第 i 层到第 n 层共有 sum 个叶子节点

假设第 i 层的节点个数有 m 个

那么在第 i 层时,这 n 个叶子节点最多能得到 2n 个子节点

因为第 i 层之后的叶子节点总数一定会大于等于 n

所以此时需要保证 m<=sum 成立

那么就能得到第 i 层的节点数 m = min(2*n,sum)

每次答案加上 m ,代表第 i 层节点最大节点个数

然后 n 等于 m-Ai ,表示第 i 层非叶子节点的个数,供 i+1 层使用

sum 减去 A[i] ,同理

※注意,如果处理过程中出现 A[i]>m ,说明无法得到这样一棵二叉树,使得满足 A0 到 Ai-1 的条件后,第 i 层的叶子节点数为 A[i]


另,如果 N 为 0,说明最大深度只到根节点过,此时 A0 必须为 1

如果 N 不为 0 且 A0 不为 0,根据条件中的 "AN≥1" 易得肯定不存在这样的二叉树




完整程序

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;

int a[100050];

void solve()
{
    int n;
    ll ans=1,m=1,sum=0;
    cin>>n;
    for(int i=0;i<=n;i++)
    {
        cin>>a[i];
        sum+=a[i];
    }
    if(n>0&&a[0]>0||n==0&&a[0]>1) //特判
    {
        cout<<"-1
";
        return;
    }
    for(int i=1;i<=n;i++)
    {
        m=min(m<<1,sum); //第i层最多节点个数
        ans+=m;
        if(a[i]>m)
        {
            cout<<"-1
";
            return;
        }
        m-=a[i]; //第i层的非叶子节点个数
        sum-=a[i]; //第i+1层往后的叶子节点个数
    }
    cout<<ans<<'
';
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    solve();
    return 0;
}

原文地址:https://www.cnblogs.com/stelayuri/p/12995196.html