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

本文共 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

你可能感兴趣的文章
springmvc + mybatis + ehcache + redis架构
查看>>
sed指定行范围匹配(转贴!)
查看>>
C#语音朗读文本 — TTS的实现
查看>>
Python正则表达式初识(十)附正则表达式总结
查看>>
APICLOUD 1.1.0 开发环境搭建
查看>>
《Cadence 16.6电路设计与仿真从入门到精通》——导读
查看>>
Confluence 6 如何让我的小组成员知道那些内容是重要的
查看>>
找到一个适合的分布式文件系统之各种分布式文件系统优缺点对比
查看>>
httpd基本配置
查看>>
索引失效的几个原因
查看>>
关于多线程中使用while做循环而不使用if的解释
查看>>
欢迎你,企业基础架构CCIE,RS CCIEv5.0的升级版新时代迎合自动化运维的网工顶级认证...
查看>>
js typoeof用法
查看>>
五险一金,你清楚吗?
查看>>
Ip核_fifo
查看>>
基础 JavaScript 实例
查看>>
自定义pageControl
查看>>
repquota命令--Linux命令应用大词典729个命令解读
查看>>
我的友情链接
查看>>
设置vs解决方案跟随右边cpp
查看>>