「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\) 的互不同构的树 ...
随机推荐
- API NEWS | Money Lover爆出潜在API漏洞
欢迎大家围观小阑精心整理的API安全最新资讯,在这里你能看到最专业.最前沿的API安全技术和产业资讯,我们提供关于全球API安全资讯与信息安全深度观察. 本周,我们带来的分享如下: Money Lov ...
- STL-priority_queue(ACM)
1.无法访问v.front().v.back() 2.是一个 堆,默认为大根堆,改造后为小根堆 大根堆 重构函数(默认)(大根堆) priority_queue<int> v; 基本操作 ...
- 一分钟学一个 Linux 命令 - find 和 grep
前言 大家好,我是 god23bin.欢迎来到<一分钟学一个 Linux 命令>系列,每天只需一分钟,记住一个 Linux 命令不成问题.今天需要你花两分钟时间来学习下,因为今天要介绍的是 ...
- 一文搞懂什么是 API
在我学习软件开发之前,API 听起来像是一种啤酒(IPA,印度淡色艾尔).如今我经常使用这个术语,事实上最近我还尝试在酒吧里点了一个 API,结果酒保给了我一个: 404 资源未找到的回应 无论是在科 ...
- Hello-FPGA CoaXPress 2.0 FPGA HOST IP Core Demo User Manual
目录 Hello-FPGA CoaXPress 2.0 Host FPGA IP Core Demo 4 1 说明 4 2 设备连接 5 3 VIVADO FPGA工程 6 4 SDK工程 9 图 1 ...
- 生成CSV文件的方法*(LIST集合为数据和生成的文件名)
/** * 生成csv文件 * @param pointsList 组织实体 * filename 生成的文件名 * list 要生成的数据 * @return */ public void Poin ...
- Istio 入门(五):访问控制和流量管理
本教程已加入 Istio 系列:https://istio.whuanle.cn 目录 4, 流量管理 基于版本的路由配置 基于 Http header 的路由配置 故障注入 两种故障注入 比例分配流 ...
- 内核源码中单个.o文件的编译过程(六)
通过对过渡篇的学习,相信你已经具有了相当的知识储备,接下来就来继续学习单个.o文件的编译过程 以/drivers/char/mem.c的编译为例 make /drivers/char/mem.o 一. ...
- 今日ERROR
树莓派插卡发烫严重 首先,我们要知道: 树莓派的指示灯可以告诉用户系统的工作状态,常见的指示灯有四个,分别是红色电源灯.绿色SD卡读写灯.黄色ACT指示灯和蓝色网络连接指示灯(仅适用于某些型号的树莓派 ...
- Win32编程
WIN32 malloc函数的底层实现是Win32API 字符编码 原始的ASCII编码最多能表示127个符号 0-7F(十六进制) 缺点:表示的符号太少了 ASCII编码的扩展:GB2312或GB2 ...