博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【文文殿下】CF1098C Construct a tree 题解
阅读量:7112 次
发布时间:2019-06-28

本文共 1463 字,大约阅读时间需要 4 分钟。

题解

挺水的一道题. Rating $ \color{orange} {2300}$ 以下送命题。

首先我们知道,所有子树大小之和就是节点个数加上从根到所有节点的路径长度之和。

他要求度数尽可能小,所以我们二分度数\(k\).显然,度数越小,子树和越大。

对于一个\(k\)叉树,他的子树大小之和为\(n+k^2+k^3+...+rem\)

我们通过二分得到最大的边界\(k\)

然后,此时我们的子树大小\(s\)是要小于等于规定的子树大小和的。

我们考虑扩大子树大小。

显然,我们让某些节点,往深度扩展将会扩大我们的子树大小。

我们记录每个深度的节点个数,已经每个节点的深度。

我们尝试从深度最深的节点开始往下扩展,直至子树大小达到规定大小。

Tips:n-1叉树的大小显然为2n-1 而一条链的大小为 n(n+1)/2 。如果k不在这个范围内,则无解。

具体实现非常简单。代码如下

#include
typedef long long ll;using namespace std;const int maxn = 1e6+10;ll n,k,cnt[maxn],d[maxn];bool check(int x) { ll i(2),j,t=1,num=k-n,dep=0; memset(d,0,sizeof d); memset(cnt,0,sizeof cnt); while(i<=n) { t*=x;++dep; for(j=1;j<=t&&i<=n;++i,++j) cnt[dep]++,d[i]=dep,num-=dep; } if(num<0) return false; j=n; while(num) { ++dep; if(cnt[d[j]]==1) --j; t = min(num,dep-d[j]); cnt[d[j]]--; d[j]+=t; cnt[d[j]]++; num-=t; --j; } return true;}int main() { cin>>n>>k; if(k<(1LL*2*n-1)||k>(1LL*n*(n+1)/2)) { puts("No"); exit(0); } int l = 1, r = n; while(l
>1; if(check(mid)) r=mid; else l = mid+1; } check(r); puts("Yes"); int pos; d[pos=1]=0; sort(d+2,d+1+n); memset(cnt,0,sizeof cnt); for(int i = 2;i<=n;++i) { while(d[pos]!=d[i]-1||cnt[pos]==r) ++pos; cout<
<<' ';cnt[pos]++; } return 0;}

转载于:https://www.cnblogs.com/Syameimaru/p/10271730.html

你可能感兴趣的文章
计算机网络之物理层笔记
查看>>
Spring的Hello World工程
查看>>
Redis学习之路(002)- Ubuntu下redis开放端口
查看>>
本地调用jni之VC++无法导入问题
查看>>
[转]谈NAND Flash的底层结构和解析
查看>>
JDBC实例代码
查看>>
通过setSystemUiVisibility实现状态栏跟Activity之间的位置关系
查看>>
Android中的单位
查看>>
PHP:php中的双引号和单引号的区别
查看>>
PersistenceContext.properties()
查看>>
中国的UED们
查看>>
【Python】python 2 map() reduce()
查看>>
阿里云域名备案之如何填写真实性核验单
查看>>
查询设计分析
查看>>
OpenWRT/LEDE长期运行记录截图
查看>>
执行计划--WHERE条件的先后顺序对执行计划的影响
查看>>
F - 概率(经典问题)
查看>>
不老的神器:安全扫描器Nmap渗透使用指南【转】
查看>>
Java-NIO(六):Channel聚集(gather)写入与分散(scatter)读取
查看>>
CUBA如何新增ServiceBean
查看>>