20240924 模拟赛 T4 题解

news/2024/9/24 22:58:10/文章来源:https://www.cnblogs.com/Scarab/p/18430258

Description

这是一道交互题。
有一棵 \(n\) 个节点的树,现在要求你通过若干次询问得到这棵树的每一条边连接哪两个点。

每次询问你需要指定 \(n\) 个整数 \(d_1,d_2,\ldots,d_n\),满足 \(-1\leq d_i\leq n\),其中 \(1\leq i\leq n\)

每次询问交互库会返回给你一个长度为 \(n\) 的布尔数组,第 \(i\) 个元素为 \(1\) 当且仅当存在某个点 \(j\) 满足 \(i,j\) 的树上距离 \(\leq d_j\),其中 \(1\leq i,j\leq n\)

定义两点的树上距离为这两点的最短路径所经过的边数。

对于所有非样例的测试点,\(n=16000\),输入的边组成一棵 \(n\) 个点的树。

子任务编号 测试点数目 标准询问次数 特殊性质
\(0\) \(3\) \(1\) 样例
\(1\) \(30\) \(300\) 树随机生成
\(2\) \(37\) \(80\)

Solution

先考虑树随机生成怎么做。

容易发现这题的随机生成方式会让树的高度为 \(O(\log n)\),所以可以先钦定根,然后用 \(O(\log n)\) 次操作确定每个点的深度。

然后考虑怎么求出每个深度内每个点的父亲。

可以对于每个二进制位考虑,具体的,先选择一个深度 \(dep\),同时枚举二进制位 \(b\),然后把 \(dep\) 这层的点中第 \(b\) 位为 \(1\) 的树的 \(d\) 设成 \(1\) 跑一遍询问,这样回答中被选中的深度在 \(dep+1\) 的点的父亲一定满足第 \(b\) 位为 \(1\)。于是就可以单次 \(\left\lceil\log_2n\right\rceil\) 次操作确定一个层所有点的父亲。这样总次数为 \(O(\log^2 n)\)

注意到上面那个东西可以让模 \(3\) 余数相等的层同时做,因为它们互不影响,于是可以做到去掉求每个点深度后 \(3\left\lceil\log_2n\right\rceil\) 次询问。

当树不是随机生成时,树的深度可能很大,\(O(dep)\) 的去求每个点的深度显然不可行。

考虑分治。假设当前分治区间为 \([l,r]\),并且已经分别知道了深度为 \([l,l]\)\([l+1,r]\) 的所有点。

\(mid=\left\lceil\frac{l+r}{2}\right\rceil\)。可以对于所有深度为 \(l\) 的点分别做长度为 \(mid-l\)\(mid-l-1\) 的询问。然后就可以对 \([l,mid-1]\)\([mid,r]\) 进行递归了。

注意到在分治的过程中同一层的区间可以一起做,同时由于同一层的相邻区间会相互影响,所以需要对于奇数和偶数区间分别做。询问次数大概为 \(92\) 次,过不了。

又因为做完 \(mid-l\) 的询问后一定可以确定递归区间分别有那些数了,所以 \(mid-l-1\) 的询问不需要奇偶分组,放到一起做即可。

加上上面那个优化后询问次数就变为 \(80\) 了,可以通过。

Code

#include <bits/stdc++.h>#ifdef ORZXKR
#include "grader.cc"
#else
#include "god.h"
#endifconst int kMaxN = 1.6e4 + 5;int n;
int d[kMaxN], dep[kMaxN], cnt[kMaxN], p[kMaxN];
bool res[kMaxN], vis[kMaxN];
std::pair<int, int> seg[kMaxN * 4];
std::vector<int> id[kMaxN], ss[30], sv[kMaxN * 4][2];namespace REAL {
void solve(int d, int x, int l, int r) {seg[x] = {l, r};if (r - l <= 1) return;int mid = (l + r + 1) >> 1;ss[d].emplace_back(x);solve(d + 1, x << 1, l, mid - 1), solve(d + 1, x << 1 | 1, mid, r);
}void getdep() {solve(1, 1, 0, n - 1);sv[1][0] = {1};for (int i = 2; i <= n; ++i) sv[1][1].emplace_back(i);for (int c = 1; c <= 20; ++c) {if (!ss[c].size()) continue;static int d[3][kMaxN];static bool res[3][kMaxN];std::fill_n(d[0] + 1, n, -1);std::fill_n(d[1] + 1, n, -1);std::fill_n(d[2] + 1, n, -1);for (int r = 0; r < 2; ++r) {for (int i = r; i < (int)ss[c].size(); i += 2) {int x = ss[c][i];std::pair<int, int> p = seg[x];int mid = (p.first + p.second + 1) / 2;for (auto j : sv[x][0]) d[r][j] = mid - p.first;}}query(d[0], res[0]);if (c != 1) query(d[1], res[1]);for (auto x : ss[c]) {std::pair<int, int> p = seg[x];int mid = (p.first + p.second + 1) / 2;for (auto j : sv[x][0]) d[2][j] = mid - p.first - 1;}query(d[2], res[2]);for (int i = 0; i < (int)ss[c].size(); ++i) {int x = ss[c][i];sv[x << 1][0] = sv[x][0];for (auto j : sv[x][1]) {if (!res[i & 1][j]) sv[x << 1 | 1][1].emplace_back(j);else if (res[2][j]) sv[x << 1][1].emplace_back(j);else sv[x << 1 | 1][0].emplace_back(j);}}}for (int i = 1; i <= 4 * n; ++i) {if (seg[i].second - seg[i].first <= 1 && (sv[i][0].size() || sv[i][1].size())) {for (auto x : sv[i][0]) dep[x] = seg[i].first; for (auto x : sv[i][1]) dep[x] = seg[i].second;}}for (int i = 1; i <= n; ++i) {id[dep[i]].emplace_back(i);}
}void getedge() {for (int r = 0; r < 3; ++r) {for (int b = 0; (1 << b) <= n; ++b) {std::fill_n(d + 1, n, -1);std::fill_n(res + 1, n, 0);for (int i = r; i <= n; i += 3) {for (auto x : id[i]) {if ((x >> b & 1)) d[x] = 1;}}if (*std::max_element(d + 1, d + 1 + n) == 1) query(d, res);for (int i = 1; i <= n; ++i)if (res[i] && dep[i] % 3 == (r + 1) % 3)p[i] |= (1 << b);}}for (int i = 2; i <= n; ++i) std::cout << p[i] << ' ' << i << '\n';
}void solve() {std::fill_n(p + 1, n, 0);std::fill_n(vis + 1, n, 0);std::fill_n(cnt, n + 1, 0);for (int i = 0; i <= n; ++i) id[i].clear();for (int i = 1; i <= 20; ++i) ss[i].clear();for (int i = 1; i <= n * 4; ++i) sv[i][0].clear(), sv[i][1].clear();getdep(), getedge();
}
} // namespace REALnamespace SAMPLE {
int fa[kMaxN];int find(int x) {return fa[x] == x ? x : fa[x] = find(fa[x]);
}void solve() {if (n == 5) return void(std::cout << "2 1\n5 3\n2 4\n2 3\n");std::fill_n(d + 1, n, -1);d[1] = 1;query(d, res);int cnt = 0;for (int i = 1; i <= n; ++i) cnt += res[i];if (cnt == 2) {for (int i = 1; i < n; ++i) std::cout << i << ' ' << i + 1 << '\n';} else {std::iota(fa + 1, fa + 1 + n, 1);for (int i = 1; i < n; ++i) {int x = rand() % n + 1, y = rand() % n + 1;while (find(x) == find(y)) {x = rand() % n + 1, y = rand() % n + 1;}std::cout << x << ' ' << y << '\n';fa[find(x)] = find(y);}}
}
} // namespace SAMPLEvoid wxy_god(int n, int subtask) {::n = n;if (subtask == 0) return SAMPLE::solve();else REAL::solve();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/803096.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

9月11日toString重载方法的使用

在编辑过程中我经常会写一部分调试一部分,至少知道哪里有错能够及时改正,在编写时发现studentManger中的打印出来的是地址,而不是自己想要的内容,经过查询是需要写toString来重载输出利用这样的方法,一是可以正常打印出自己想要的内容,而是可以根据一个参数打印出所有的信…

软件工程作业——结对项目

这个作业属于哪个课程 22级计科12班这个作业要求在哪 作业要求这个作业的目标 实现一个自动生成小学四则运算题目的命令行程序成员姓名 学号 GitHub地址吕宏鸿 3122004446 结对项目宋观瑞 3122004402 结对项目1.PSP表格PSP2.1 预估耗时(分钟) 实际耗时(分钟)计划 10 5* 估计…

9月10日循环条件的结束

在测试编程中涉及到输入错误要重新返回UI界面,但是我写的总是输入不管是对还是错都会直接结束程序,完全不符合要求,经过整理思路,查询代码结构,此处应该设计为双层循环外部为while,内部为witch case语句,当输入为1时执行case==1;经应该是执行生产计划类然后跳出witch条…

IDEA更改远程git仓库地址

前言 我们在使用IDEA开发时,一般会配置好对应的git仓库,这样就比较容易对代码进行控制以及协同开发。但有时候,我们远程的仓库地址由于这样那样的原因,需要迁移(这在爱折腾的企业是常有的事情)。那么,我们该如何在IDEA中更新远程仓库地址呢? 如何设置 首先,我们点击上…

vue3开发中易遗漏的常见知识点

组件样式的特性 Scoped CSS之局部样式的泄露 示例(vue3): 父组件: <template><h4>App Title</h4><hello-world></hello-world> </template> <script> import HelloWorld from ./HelloWorld.vue;export default {name: App,compo…

PasteForm最佳CRUD实践,实际案例PasteTemplate详解(一)

本文将介绍soft.pastecode.cn出品的PasteForm,PasteForm是贴代码使用Dto思想实现的CRUD的一个组件,或者说输出一个思想! 为啥我觉得是最佳的CRUD呢?先结合你的实际项目解答下以下问题: 1.如果有一个系统,有100个表,你的管理端需要多少页面?别和我说100个表很多,需求复…

RTE大会报名丨 重塑语音交互:音频技术和 Voice AI,RTE2024 技术专场第一弹!

Voice AI 实现 human-like 的最后一步是什么?AI 视频爆炸增长,新一代编解码技术将面临何种挑战?当大模型进化到实时多模态,又将诞生什么样的新场景和玩法?所有 AI Infra 都在探寻规格和性能的最佳平衡,如何构建高可用的云边端协同架构?AI 加持下,空间计算和新硬件也迎来…

彻底搞懂回溯算法

1.回溯算法的核心思想 回溯算法的核心思想是:尝试+记录+回退。 先尝试一种选项,在选择该选项的前提下继续寻解,如果最后寻解成功,则记录这个解,否则不用记录,然后再回退到选择该选项前的状态,改为尝试其它选项再继续寻解,判断其它选项是不是解。 2.回溯算法的关键点 回溯…

9.23 ~ 9.29

集训9.23 集训第一天。 早晨因为太多人没拿早读资料被老登 D 了。 不是哥们你不早说 现在我上哪给你找资料去 😅 上午模拟赛。 发现 T1 的图挂了,于是看形式化题意;初始有一张 \(n\) 个点的完全图,接着删除 \(m\) 条边。 询问有多少长度为 \(13\) 的序列 \(p_1,...,p_{13}…

CSP 集训记录

用来整理模拟赛等9.23 csp-3【noip23 ZR二十连测 DAY10】 保龄. A.奇观 狗市题目描述。不是这题意太大歧义了吧,我讨厌的第二种出题人——题意描述相当不清。CTH:13 座城市又不代表是 13 座不同的城市。直接看形式化题目的话(如果能看懂要干什么)那这题确实不难。 解: 容易…

判断系统大小端字节序的方法

1、字节序 1.1、大端字节序(big-endian) 数据低位存储在高地址位,数据高位存储在低地址位。 假设定义一个变量并赋予初值: int a = 0x12345678; 对于这个整型数据,一共有四个字节,假设为其分配的地址空间为0x1001~0x1004,则从低位到高位,每个字节依次是:12、34、56、78。…

第二十四讲:MySQL是怎么保证高可用的?

为了让各位更好的了解文章,我归纳了下面几点最重要的: 1、MySQL 高可用系统的可用性,是依赖于主备延迟的。延迟的时间越小,主库故障的时候,服务恢复需要的时间就越短,可用性就越高。 2、主备延迟原因:备库用的机子不行(IOPS是和主库相同的,不要轻视备库)、备库压力太…