【周赛第70期】4题(2题未测试) 启发式合并 哈希表 最近公共祖先 堆 数学

目录

  • ~~本次比赛前两题似乎没有数据,所以代码可能有隐藏的错误~~
    • TODO 如果用时间的话,准备自己造一些数据测一下。
  • 1、题目名称:小张的手速大比拼
    • 题目
    • 答案
      • 启发式合并
      • 另一种思路(非正解,未经充分测试)
  • 2、题目名称:坐公交
    • 题目
    • 答案
  • 3、题目名称:三而竭
    • 题目
    • 答案
  • 4、题目名称:争风吃醋的豚鼠
    • 题目
    • 答案

本次比赛前两题似乎没有数据,所以代码可能有隐藏的错误

TODO 如果用时间的话,准备自己造一些数据测一下。

1、题目名称:小张的手速大比拼

题目

在很久很久以前,小张找到了一颗有 N 个节点的有根树 T 。 树上的节点编号在 1 到 N 范围内。 他很快发现树上的每个节点 i 都有一个对应的整数值 V[i]。 一个老爷爷对他说,给你一个整数 X, 如果你能回答我的 M 个问题,他就给张浩扬购买一些零食。 对于每个问题 Q[i], 请你找到 在 T 中以节点 Q[i] 为根的子树中的所有节点(包括 Q[i])中, 有没有两个节点 A, B (A != B) 的值 V[A] ^ V[B] 的异或和为 X。 如果有这样的两个节点, 请你输出 YES。 否则你需要输出 NO 表示没有节点符合上面的条件。

答案

启发式合并

关于启发式合并,可以参考: OI Wiki 启发式合并
对于每个子树,以大小最大的子树为基础,每次将根节点或其它较小子树合并进去。
子树 YES,必然有当前树 YES。

不太确定复杂度怎么算,以下不一定对……
大概是考虑所有值被加入集合(哈希表)的总次数,每次O(1)。
对于任意一个节点,它的重子树不需要再次被加入哈希表,其他子树需要再次加入哈希表,最坏情况子树节点数一样大,累计O((子树个数-1)*单个子树节点数)=O(总节点数-单个子树节点数),全加起来是O(总结点数+总结点数*(1-1/子树个数)+总结点数*(1-1/子树个数)^2+...) = O(总结点数*[1+(1-1/子树个数)+(1-1/子树个数)^2+...])
假设树有h层,每层k个分支,则有1+k+k^2+...+k^(h-1) = n = (k^h-1)/(k-1) < k^h
O(n*[1+((k-1)/k)+((k-1)/k)^2+...+((k-1)/k)^(h-1)]) = O(n*[k^h-(k-1)^h]/[k^(h-1)]) = O(n)

#include<bits/stdc++.h>using namespace std;
const int N = 101000;
int n, x, m;
vector<int> e[N];
int value[N];
int sz[N], son[N];void dfs(int u) {sz[u] = 1;for (const auto &v: e[u]) {dfs(v);sz[u] += sz[v];if (son[u] == 0 || sz[son[u]] < sz[v]) {son[u] = v;}}
}bool ans[N];unordered_set<int> work(int u) {if (!son[u]) {return {value[u]};}auto now = work(son[u]);if (ans[son[u]]) {ans[u] = true;}if (now.count(value[u] ^ x)) {ans[u] = true;}now.insert(value[u]);unordered_set<int> tmp;for (const auto &v: e[u]) {if (v == son[u])continue;tmp = work(v);if (ans[v]) {ans[u] = true;}if (!ans[u]) {for (const auto &it: tmp) {if (now.count(it ^ x)) {ans[u] = true;break;}now.insert(it);}}}return now;
}int main() {cin >> n >> x >> m;int rt = -1;for (int i = 1, fa; i <= n; i++) {scanf("%d", &fa);if (fa == -1) {rt = i;} else {e[fa].push_back(i);}}for (int i = 1; i <= n; i++)scanf("%d", &value[i]);dfs(rt);work(rt);int q;for (int i = 1; i <= m; i++) {scanf("%d", &q);puts(ans[q] ? "YES" : "NO");}return 0;
}

另一种思路(非正解,未经充分测试)

树中两个节点的值异或为x,导致包含它们的最近公共祖先的子树返回YES。
所以先标记最近公共祖先,再dfs2标记最近公共祖先直到根节点。

但是如果整个树的节点值只有两种,时间复杂度O(n^2)

#include<bits/stdc++.h>using namespace std;const int N = 101000;
int n, x, m;
vector<int> e[N];
int dep[N], f[N][20];
unordered_map<int, vector<int>> mp;
bool ans[N];void dfs(int u) {for (int i = 1; i < 20; i++) {f[u][i] = f[f[u][i - 1]][i - 1];}for (const auto &v: e[u]) {dep[v] = dep[u] + 1;f[v][0] = u;dfs(v);}
}int getLCA(int u, int v) {if (dep[u] < dep[v]) {swap(u, v);}for (int i = 19; i >= 0; i--) {if (dep[f[u][i]] >= dep[v]) {u = f[u][i];}}if (u == v) {return u;}for (int i = 19; i >= 0; i--) {if (f[u][i] != f[v][i]) {u = f[u][i];v = f[v][i];}}return f[u][0];
}void dfs2(int u) {for (const auto &v: e[u]) {dfs2(v);ans[u] |= ans[v];}
}int main() {cin >> n >> x >> m;int rt = -1;for (int i = 1, fa; i <= n; i++) {scanf("%d", &fa);if (fa == -1) {rt = i;} else {e[fa].push_back(i);}}dep[rt] = 1;dfs(rt);for (int i = 1, value; i <= n; i++) {scanf("%d", &value);const auto &vList = mp[value ^ x];for (const auto &v: vList) {ans[getLCA(i, v)] = true;}mp[value].push_back(i);}dfs2(rt);int q;for (int i = 1; i <= m; i++) {scanf("%d", &q);puts(ans[q] ? "YES" : "NO");}return 0;
}
/*不是比赛时的用例
5 3 5
-1 1 1 3 3
1 2 1 2 1
1 2 3 4 5*/

2、题目名称:坐公交

题目

公交上有N排凳子,每排有两个凳子,每一排的凳子宽度不一样。有一些内向和外向的人按照顺序上车。 外向的人(0):只会选择没人的一排坐下,如果有很多排符合要求,他会选择座位宽度最小的坐下。 内向的人(1):只会选择有人的一排坐下,如果有很多排符合要求,他会选择座位宽度最大的坐下。 数据保证存在合理。输出每个人所在的排。

答案

题面应该是把内向外向说反了,明明内向才自己坐……
间接排序得到大小序号。
外向找没人的坐,会按顺序坐,坐完后内向的就可以坐了,所以将大小序号入堆。
内向找有人的最大的坐,也就是将堆顶弹出。O( nlogn )

#include<bits/stdc++.h>using namespace std;
const int N = 101000;
int n;
int len[N], r[N];
char s[N * 2];int main() {cin >> n;for (int i = 1; i <= n; i++) {scanf("%d", &len[i]);r[i] = i;}sort(r + 1, r + n + 1, [](int a, int b) {return len[a] < len[b];});
//for(int i=1;i<=n;i++){
// cout<<i<<" : "<<r[i]<<endl;
// }scanf("%s", s + 1);int pos = 0;priority_queue<int> q;for (int i = 1; i <= n * 2; i++) {if (s[i] == '0') {++pos;printf("%d ", r[pos]);q.push(pos);} else {int now = q.top();q.pop();printf("%d ", r[now]);}}return 0;
}

3、题目名称:三而竭

题目

一鼓作气再而衰三而竭。 小艺总是喜欢把任务分开做。 小艺接到一个任务,任务的总任务量是n。 第一天小艺能完成x份任务。 第二天能完成x/k。 。。。 第t天能完成x/(k^(t-1))。 小艺想知道自己第一天至少完成多少才能完成最后的任务。

答案

印象中见过完全一样的题……
份数是整数,相当于每次取整。
第1天x,可以表示为x=a1+a2k+…+ank^(n-1) (0<=ai<k)
第2天 a2+a3k+…+ank^(n-2)

第n天an

总数a1+a2*(k+1)+a3*(k ^2+k+1)+…+an*(k ^(n-1)+…+1) >= n
可以对n取模,每次模(k ^(n-1)+…+1) (k ^(n-2)+…+1) … (k+1) (1)
可以求出an…a1
代入x=a1+a2k+…+ank^(n-1)
可以求出答案。

#include <iostream>
#include <string>
#include <sstream>
#include <vector>using namespace std;
using LL = long long;
const int N = 1010;
LL pk[N];
LL sum[N];int main() {LL n, k;cin >> n >> k;pk[0] = 1;sum[0] = pk[0];for (int i = 1; i < N; i++) {pk[i] = pk[i - 1] * k;sum[i] = sum[i - 1] + pk[i];}int pos = 0;for (; n / sum[pos] >= k; pos++) {}LL ans = 0;for (int i = pos; i >= 0; i--) {ans += n / sum[i] * pk[i];n %= sum[i];}cout << ans << endl;return 0;
}

4、题目名称:争风吃醋的豚鼠

题目

N个节点两两建边。 不存在3个节点相互之前全部相连。(3个节点连接成环) 最多能建立多少条边?

答案

二分图性质。
一开始画来画去想了半天

#include <iostream>
#include <string>
#include <sstream>
#include <vector>using namespace std;
using LL = long long;int main() {LL n;cin >> n;cout << (n / 2) * ((n + 1) / 2) << endl;return 0;
}

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

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

相关文章

重构内置类Function原型上的call方法

重构内置类Function原型上的call方法 // > 重构内置类Function原型上的call方法 ~(function () {/*** call: 改变函数中的this指向* params* context 可以不传递&#xff0c;传递必须是引用类型的值&#xff0c;因为后面要给它加 fn 属性**/function myCall(context) {/…

最佳实践:Swagger 自动生成 Api 文档

目录 Tapir 介绍 为什么使用 Tapir 快速使用 Tapir 添加依赖 定义一个端点(Endpoint) 生成 Swagger ui 根据 yaml 生成 endpoint 自动生成 API 文档的好处不言而喻&#xff0c;它可以提供给你的团队或者外部协作者&#xff0c;方便 API 使用者准确地调用到你的 API。为了…

list的使用和模拟实现

目录 1.list的介绍及使用 1.1 list的介绍 1.2 list的使用 1.2.1 list的构造 1.2.2 list iterator的使用 1.2.3 list capacity 1.2.4 list element access 1.2.5 list modifiers 2.为什么使用迭代器&#xff1f; 3.list的模拟实现 3.1完整代码 3.2代码解析 4.list与…

YOLOv5-7.0实例分割+TensorRT部署

一&#xff1a;介绍 将YOLOv5结合分割任务并进行TensorRT部署&#xff0c;是一项既具有挑战性又令人兴奋的任务。分割&#xff08;Segmentation&#xff09;任务要求模型不仅能够检测出目标的存在&#xff0c;还要精确地理解目标的边界和轮廓&#xff0c;为每个像素分配相应的…

Spring Boot配置文件与日志文件

1. Spring Boot 配置文件 我们知道, 当我们创建一个Spring Boot项目之后, 就已经有了配置文件存在于目录结构中. 1. 配置文件作用 整个项目中所有重要的数据都是在配置文件中配置的&#xff0c;比如: 数据库的连接信息 (包含用户名和密码的设置) ;项目的启动端口;第三方系统的调…

KMP字符串 (简单清晰/Java)

Kmp算法 解决问题&#xff1a; 字符串匹配问题 怎么解决&#xff1f; 前缀表next[]数组 #分析 先看暴力做法&#xff1a; 两层for循环&#xff0c;一层遍历文本串&#xff0c;一层遍历模式串&#xff08;子串&#xff09;对应的每个字符进行匹配&#xff0c;匹配成功就 i &a…

大数据——协同过滤推荐算法:线性回归算法

推荐系统中的协同过滤算法一般分为两大类&#xff1a; 基于行为的协同过滤算法(Memory-Based CF)&#xff0c;利用用户行为数据计算相似度&#xff0c;包括用户之间的相似度和物品之间的相似度。基于模型的协同过滤算法(Model-Based CF)&#xff0c;利用机器学习算法预测用户的…

华纳云:Ubuntu安装Drupal报错怎么解决

在安装 Drupal 过程中遇到错误可能是由于各种原因引起的。以下是一些常见的安装 Drupal 时可能遇到的问题以及相应的解决方法&#xff1a; 数据库连接问题&#xff1a; 安装 Drupal 时需要连接数据库&#xff0c;如果数据库连接配置不正确&#xff0c;可能会导致安装失败。确保…

如何将jar包部署到宝塔

尝试多种方式上传&#xff0c;但启动一直失败&#xff0c;这种方式亲测是好使的 项目内修改位置 在pom.xml文件中将mysql的scope改成provided&#xff0c;如果是固定的版本号会出现问题 之后就可以打包啦&#xff0c;直接点击maven中的package 找到打包文件的位置&#xff…

Object.values()

Object.values() 是ES2017新增的一个对象方法,它可以将一个对象自身的所有可枚举属性值,组成一个数组返回。 基本语法: Object.values(obj)示例: jsCopy codeconst obj {foo: bar,baz: 42 };Object.values(obj); // [bar, 42]Object.values()的特点: 只返回可枚举的属性值…

免费插件-illustrator-Ai插件-印刷功能-二维码生成

文章目录 1.介绍2.安装3.通过窗口>扩展>知了插件4.功能解释5.示例5.1.QR常用二维码5.2.PDF4175.3.EAN13 6.总结 1.介绍 本文介绍一款免费插件&#xff0c;加强illustrator使用人员工作效率&#xff0c;进行二维码生成。首先从下载网址下载这款插件 https://download.csd…

MySQL之深入InnoDB存储引擎——redo日志

文章目录 一、为什么需要redo日志二、redo日志的类型1&#xff09;简单的redo日志类型2&#xff09;复杂的redo日志类型 三、Mini-Transaction四、redo日志的写入过程五、redo日志文件1、刷盘时机2、redo日志文件组 六、log sequence number1、lsn的引入2、flushed_to_disk_lsn…

npm ERR! cb.apply is not a function

当NPM版本过低导致 npm ERR! cb.apply is not a function 1. win r 打开运行&#xff0c;输入%appdata% 2. 删除 npm 和 npm-cache 文件夹 3. 执行npm cache clean --force命令 如果还不行&#xff0c;就执行卸载Node.js重新安装。

java 文件/文件夹复制,添加压缩zip

复制文件夹,并压缩成zip 需求&#xff1a;创建A文件夹&#xff0c;把B文件夹复制到A文件夹。然后把A文件夹压缩成zip包 public static void main(String[] args) throws Exception {try {String A "D:\\dev\\program";String B "D:\\program";// 创建临…

Vue 插槽 slot

solt 插槽需要分为 2.6.0 版本以上和 2.6.0版本以下。 2.6.0 版本以下的 slot 插槽在&#xff0c;2.x版本将继续支持&#xff0c;但是在 Vue 3 中已被废弃&#xff0c;且不会出现在官方文档中。 作用 插槽 prop 允许我们将插槽转换为可复用的模板&#xff0c;这些模板可以基于…

Qt应用开发(基础篇)——LCD数值类 QLCDNumber

一、前言 QLCDNumber类继承于QFrame&#xff0c;QFrame继承于QWidget&#xff0c;是Qt的一个基础小部件。 框架类QFrame介绍 QLCDNumber用来显示一个带有类似lcd数字的数字&#xff0c;适用于信号灯、跑步机、体温计、时钟、电表、水表、血压计等仪器类产品的数值显示。 QLCDNu…

【CSS】文本效果

文本溢出、整字换行、换行规则以及书写模式 代码&#xff1a; <style> p.test1 {white-space: nowrap; width: 200px; border: 1px solid #000000;overflow: hidden;text-overflow: clip; }p.test2 {white-space: nowrap; width: 200px; border: 1px solid #000000;ove…

2023年Q2天猫洗衣机行业品牌销售排行榜(淘宝天猫数据)

洗衣机作为普及率极高的家电之一&#xff0c;如今已经成为我们生活中不可或缺的一部分。由于洗衣机的普及率较高&#xff0c;因此虽其市场规模庞大&#xff0c;但如今要使洗衣机呈现规模化增长的可能性还是比较小的。不过&#xff0c;随着用户需求及产品的升级&#xff0c;洗衣…

【C++中的pair类型】用于将两个不同类型的元素组合成一个单元,即key-value

文章目录 1、定义和初始化2、使用方式 1、定义和初始化 pair<type1, type2> p; // 初始化方法有3种 pair<int, string> p make_pair(1, "one"); pair<int, string> p {1, "one"}; pair<int, string> p(1, "one");2、…

【docker】 运行bytetrack 构建映像失败 使用docker删除之前构建的映像

1 Docker删除docker build失败的images docker images | grep "<none>" | awk {print $3} | xargs docker rmi 2 Docker删除启动失败的image docker ps -a | awk {if (length($2) 12){print $1}} | xargs docker rm