「codeforces - 1481F」AB Tree
理一下逻辑,主要讲一下我做题时的疑惑和其它题解没提到的细节。
首先容易看到,一个必然不劣的贪心策略是把尽量靠近根的层铺成同样的字符。也许会有疑惑,字符串是否本质不同的判定每个位置地位相等。然而在这题里面字符串个数的贡献是和结点所为根的子树大小有关的,所以这个贪心不劣。
设树的最大深度为 \(d\),那么如果我们能实现每层都铺成同样的字符,答案就是不同长度的字符串个数,也就是 \(d\)。
考虑构造出答案为 \(d+1\) 的情况,这时候贪心就跑不出来了,具体情况是,会出现一层既有 a 又有 b,其他层都是 pure a 或 pure b。
主要问题就在于 miscellaneous level 放在哪里,才能让答案最小。直觉地,我们认为把它放在尽量低(离根更远)的 level 会更优。但是其实贡献结束的地方是叶子,所以其实我们应该把它放在叶子尽量多的 level。这个时候答案为 \(d+1\)。
根据以上的推理,我们得出一个论断:最优答案在 \(d\) 和 \(d+1\) 出现。剩下的问题就是如果判断是前者还是后者。
其实这是一个简单可达性 dp 可以解决的问题,将每一个 level 压成一个 item,其体积为当层的结点个数。但是这个是 \(O(n^2)\) 的,要考虑优化。有两种解决的道路,分析后可以发现一个根号规模的结论,或者用 std::bitset 优化 dp。
注意 std::bitset 优化 dp 后状态略有不同……
#include<bits/stdc++.h>
#define cmin(x, y) x = std::min(x, y)
#define cmax(x, y) x = std::max(x, y)
#define fors(i, l, r, ...) for(int i = (l), REP##i = (r), ##__VA_ARGS__; i <= REP##i; ++i)
#define dfors(i, r, l, ...) for(int i = (r), REP##i = (l), ##__VA_ARGS__; i >= REP##i; --i)
// observation: amount different answers would be 2: maximum depth, or, it plus 1
int n, _x, dep[100100], nod[100100], leaf[100100], len, vol[100100];
// params: @nod[i]: amout of nodes at level i; @leaf[i]: amout of leaves at lv i;
// #vol[i]: volume of i-th item
std::bitset<100100> f[2100]; // if can assign it to j perfectly within lefmost i items
std::vector<int> adj[100100], zip[100100];
void pre_dfs(const int x) {
nod[dep[x]]++,leaf[dep[x]] += adj[x].empty();
for(const int y : adj[x]) dep[y] = dep[x]+1,pre_dfs(y);
}
int pre_zip() {
static int vis[100100], tot;
fors(i, 1, len) {
if(!vis[nod[i]]) vol[vis[nod[i]] = ++tot] = nod[i];
zip[vis[nod[i]]].emplace_back(i);
}
return tot; // amount of items
}
signed main() {
std::ios_base::sync_with_stdio(0);
std::cin.tie(0);
std::cin >> n >> _x;
fors(i, 1, n-1, f) std::cin >> f,adj[f].emplace_back(i+1);
pre_dfs(dep[1] = 1),len = *std::max_element(dep+1, dep+n+1); // processing basic information
int m = pre_zip(); // compressing levels with same amout of nodes
fors(i, f[0][0] = 1, m, tmp) {
f[i] = f[i-1],tmp = zip[i].size();
for(int j = 1; j <= tmp; j *= 2) tmp -= j,f[i] |= (f[i]<<(vol[i]*j));
if(tmp > 0) f[i] |= (f[i]<<(vol[i]*tmp));
}
std::vector<bool> k(len);
std::function<void(int, int)> find_path = [&](const int rem, int t) { // reviving way we DP through
if(rem == 0) return;
for(const int x : zip[rem]) {
if(vol[rem] > t || f[rem-1][t]) break;
t -= vol[rem],k[x-1] = 1;
}
find_path(rem-1, t);
};
if(f[m][_x]) { // when greedy strategy runs well
std::cout << len << "\n";
find_path(m, _x);
fors(i, 1, n) std::cout << (k[dep[i]-1]?'a':'b');
return std::cout << "\n", 0;
}
std::cout << len+1 << "\n"; // otherwise the answer would be maximum depth plus 1
int tmp = std::numeric_limits<int>::max(), tmp1 = -1;
dfors(i, _x, 0) if(f[m][i]) {
tmp = i; break;
}
find_path(m, tmp);
fors(i, 1, len) if(!k[i-1] && leaf[i] >= _x-tmp) {
tmp1 = i; break;
}
fors(i, 1, n) {
if(dep[i] == tmp1 && adj[i].empty()) std::cout << (tmp == _x?'b':(++tmp, 'a'));
else std::cout << (k[dep[i]-1]?'a':'b');
}
return std::cout << "\n", 0;
}
「codeforces - 1481F」AB Tree的更多相关文章
- 「算法笔记」Link-Cut Tree
一.简介 Link-Cut Tree (简称 LCT) 是一种用来维护动态森林连通性的数据结构,适用于动态树问题. 类比树剖,树剖是通过静态地把一棵树剖成若干条链然后用一种支持区间操作的数据结构维护, ...
- 「CodeForces 581D」Three Logos
BUPT 2017 Summer Training (for 16) #3A 题意 给你三个矩形,需要不重叠不留空地组成一个正方形.不存在输出-1,否则输出边长和这个正方形(A,B,C表示三个不同矩形 ...
- 「CodeForces - 50C 」Happy Farm 5 (几何)
BUPT 2017 summer training (16) #2B 题意 有一些二维直角坐标系上的整数坐标的点,找出严格包含这些点的只能八个方向走出来步数最少的路径,输出最少步数. 题解 这题要求严 ...
- 「CodeForces - 598B」Queries on a String
BUPT 2017 summer training (for 16) #1I 题意 字符串s(1 ≤ |s| ≤ 10 000),有m(1 ≤ m ≤ 300)次操作,每次给l,r,k,代表将r位置插 ...
- 「CodeForces - 717E」Paint it really, really dark gray (dfs)
BUPT 2017 summer training (for 16) #1H 题意 每个节点是黑色or白色,经过一个节点就会改变它的颜色,一开始在1节点.求一条路径使得所有点变成黑色. 题解 dfs时 ...
- 「CodeForces 476A」Dreamoon and Stairs
Dreamoon and Stairs 题意翻译 题面 DM小朋友想要上一个有 \(n\) 级台阶的楼梯.他每一步可以上 \(1\) 或 \(2\) 级台阶.假设他走上这个台阶一共用了 \(x\) 步 ...
- 「CodeForces 546B」Soldier and Badges 解题报告
CF546B Soldier and Badges 题意翻译 给 n 个数,每次操作可以将一个数 +1,要使这 n 个数都不相同, 求最少要加多少? \(1 \le n \le 3000\) 感谢@凉 ...
- 「Codeforces 79D」Password
Description 有一个 01 序列 \(a_1,a_2,\cdots,a_n\),初始时全为 \(0\). 给定 \(m\) 个长度,分别为 \(l_1\sim l_m\). 每次可以选择一个 ...
- 「Codeforces 468C」Hack it!
Description 定义 \(f(x)\) 表示 \(x\) 的各个数位之和.现在要求 \(\sum_{i=l}^rf(i)\bmod a\). 显然 ans=solve(l,r)%a; if(a ...
- 「Codeforces 724F」Uniformly Branched Trees
题目大意 如果两棵树可以通过重标号后变为完全相同,那么它们就是同构的. 将中间节点定义为度数大于 \(1\) 的节点.计算由 \(n\) 个节点,其中所有的中间节点度数都为 \(d\) 的互不同构的树 ...
随机推荐
- Kubernetes(k8s)定时任务:CronJob
目录 一.系统环境 二.前言 三.Kubernetes CronJob简介 四.kubernetes CronJob和Linux crontab对比 五.CronJob表达式语法 六.创建CronJo ...
- 为什么说 Go 语言字符串是不可变的?
原文链接: 为什么说 Go 语言字符串是不可变的? 最近有读者留言说,平时在写代码的过程中,是会对字符串进行修改的,但网上都说 Go 语言字符串是不可变的,这是为什么呢? 这个问题本身并不困难,但对于 ...
- R 语言中常见的 10 个错误,看到第 7 个会不会感觉很神奇?
翻译:BioIT 爱好者(部分内容有调整)原文:The top 10 R errors, the 7th one will surprise you 就像你学习走路时遇到了一些问题,你在学习 R 的过 ...
- 在技术圈混,不知道这些你就 OUT 了
技术之路就是漫长的打怪升级,不断学习前人的踩坑经验才能提升自己,切忌闭门造车.所谓独乐乐不如众乐乐,强烈推荐以下公众号,让你的生活多点意思,希望小伙伴们能在 coding 的路上走的更远. OSC开源 ...
- 腾讯云 cloudbase 云开发使用笔记
产品概述 云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为开发者提供高可用.自动弹性扩缩的后端云服务,包含计算.存储.托管等 serverless ...
- awk 内置变量与自定义变量
点击上方" 生信科技爱好者 ",马上关注 真爱,请置顶或星标 作者:ghostwu 原文:https://www.cnblogs.com/ghostwu/p/9085653.htm ...
- Nucleic Acids Research上关于生物医学分析Galaxy平台在几个独立面上的最新发展。
该平台的官方主服务器拥有超过124000注册用户,每月新注册用户~2000。平均而言,......
本文分享自微信公众号 - 生信科技爱好者(bioitee).如有侵权,请联系 support@oschina.cn 删除.本文参与"OSC源创计划",欢迎正在阅读的你也加入,一起分 ...
- 预测 motif 的计算原理
本文章来源于简书,作者小潤澤,已获原作者授权:部分内容有调整. 前言 蛋白质中功能的基本单元是 domain,是一种特殊的三维结构,不同结构的 domain 与其他分子特异性结合从而发挥功能.与此类似 ...
- 10.5. 版本控制(如Git)
版本控制系统(Version Control System,VCS)是软件开发过程中用于管理源代码的工具.它可以帮助你跟踪代码的变更历史,方便回滚到之前的版本,以及协同多人共同开发.Git是当前最流行 ...
- 寻找一个好的工程师不只是看ta的刷题能力
面试一个工程师,该考察什么能力,如果单单背诵一些概念.题目好像是在考察记忆力,最终项目里还是得解决实际问题.但解决实际问题的能力真的不易考察,导致大部分公司面试前期都只能通过试题来筛选求职者,到面试后 ...