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;
}