当前位置: 首页 > article >正文

【例题2】The XOR Largest Pair(信息学奥赛一本通- P1472)

【题目描述】在给定的 N 个整数 A1,A2,…,AN 中选出两个进行异或运算得到的结果最大是多少【输入】第一行一个整数 N。第二行 N 个整数 Ai​​ 。【输出】一个整数表示答案。【输入样例】5 2 9 5 7 0【输出样例】14【提示】对于 100% 的数据1≤N≤10^5,0≤Ai2^31​​ 。题目分析本题是一道极其经典的算法面试与竞赛题要求在一个长度为 N 的数组中找出两个数字使得它们的异或XOR结果最大。 数据范围给到了 N≤10^5如果采用暴力的双重for循环两两匹配时间复杂度是 O(N^2)运算次数高达 10^10 级别毫无悬念会超时。这就逼迫我们必须寻找一个 O(Nlog(maxA)) 级别的高效算法。处理“最大异或值”问题的绝对标配就是01字典树。解题思路与思考过程异或运算的核心法则是相同为 0不同为 1。 要想让异或得到的值尽量大在二进制表示下我们必须秉持一个极其贪心的策略高位的 1 绝对比低位的 1 更重要。因此当我们拿着一个数字 X 去找它的“最佳异偶”时我们希望从它的最高位开始每一位都尽量找和它相反的数。思路演进初级思维字符串具象化最直观的想法是把所有的整数像十进制转二进制那样用%2和/2拆开存进vector补齐前导 0 后拼接成string然后当成普通的英文字符串插入字典树。这种做法逻辑上是通的也最符合人类的直觉思维。进阶思维位运算在计算机底层整数本身就是以 32 位二进制的形式静态躺在内存里的我们根本不需要脱裤子放屁去借助vector和string拆解它。直接利用位运算(xi)1就能在 1 个 CPU 时钟周期内瞬间精准提取出我们要的第 i 位是 0 还是 1。算法设计建树Insert把数组中所有的数从最高有效位第 30 位到最低位第 0 位依次取出其二进制的 0 或 1插入到一棵只有两个分叉0 通道和 1 通道的字典树中。查询Query拿着数字 X同样从最高位开始在树上遍历。取出 X 的当前位 Y。我们极其渴望走与它相反的路径 ZYˆ1。如果字典树中 Z 路径存在nxt[Z]!0果断走进去并且让最终答案累加 2^i因为这一位异或出了 1。如果 Z 路径不存在被逼无奈只能走相同的路径 Y。这一位异或结果为 0答案不累加。统计让数组里的每个数字都去树上跑一遍query维护全局最大值。时空复杂度分析时间复杂度每个数字插入和查询都需要遍历 31 位。建树复杂度为 O(31×N)查询复杂度为 O(31×N)。总体时间复杂度为 O(N)严格来说是 O(Nlog(maxA))面对 10^5 的数据运算不过几百万次速度极快。空间复杂度由于每个数字最多贡献 31 个节点总节点数不会超过 31×10^5。采用静态数组tree[4000000][2]空间复杂度为 O(Nlog(maxA))在正常内存限制内绝对安全。坑点总结pow函数的精度刺客使用cmath里的pow(2,k)计算 2 的次幂返回的是浮点数。在位数较高时极易因浮点精度丢失导致最终转成int时少 1。必须使用位运算1k来代替。字典树通道有效性判定判断一个节点是否存在是看它的nxt是否被分配过有效编号即nxt[v]!0不能写成nxt[v]1这会导致只认第一个分配的节点丢弃后续所有路径。0 的边界死角如果采用除 2 取余法拆解数字遇到 x0 时while(x!0)会直接跳过导致存入空串。位运算写法天然免疫此问题。两个版本代码的区别与演进下面展示这段代码的进化史。版本一普通字典树写法把十进制转二进制、位数对齐补 0、反转拼接成字符串的逻辑强行闭环非常直观但由于频繁申请vector和string内存常数极大且存在pow精度风险。版本二纯位运算标程剔除了所有多余的容器直接操作底层二进制位代码极度精简执行效率是版本一的数十倍以上属于竞赛必背的满分模板。版本一直观具象化写法普通字典树思想//普通字典树写法 可以全部ac 但是常数开销大 #include iostream #include algorithm//对应max函数 #include cmath//对应pow函数 算法竞赛中极不推荐用pow算2的次幂 #include vector using namespace std; int n; //a数组里每一行是一个vector用来暂存每个数字拆解后的二进制位 //注意由于是x%2拆解存入的顺序是 从低位到高位 vectorint a[100010];//存整数转换为二进制的结果 int sum;//计算最后异或结果的最大值 //字典树节点 struct treenode{ //状态转移表记录通往0和1两个方向的下一个节点编号门牌号 //里面存的是整数编号不能当成bool值来判断1 int nxt[2]; }tree[4000000]; int pc;//记录当前开辟到了第几个节点 //字典树插入(接受纯0/1组成的字符串) void insert(string s){ int p0;//每一轮从根节点开始 int lens.size(); for(int i0;ilen;i){ //如果该字符分支不存在 就开辟一个新空间给到它 if(tree[p].nxt[s[i]-0]0) tree[p].nxt[s[i]-0]pc; //更新指针位置 继续往下走 ptree[p].nxt[s[i]-0]; } } int main(){ ios::sync_with_stdio(false); cin.tie(0); cinn; int len10;//存储所有整数转化为二进制后最长的那个位数 //先把所有整数转化为二进制数存起来 //a里面每一行存的是每一个整数二进制表示下从低位到高位 for(int i1;in;i){ int x; cinx; //先把x转换为二进制存储到a数组中 while(x!0){ a[i].push_back(x%2);//剥离最后一位 xx/2;//右移一位 } int len2a[i].size(); //更新最大二进制位数 len1max(len1,len2); } //接下来把每个整数位数不足len1的都在最后补0最高位 for(int i1;in;i){ //当前整数总位数 int len2a[i].size(); //补len1-len2个0 for(int j1;jlen1-len2;j) a[i].push_back(0); } //接下来把a每一行倒着存进s //这样就可以实现高位在前 低位在后 for(int i1;in;i){ string s; //倒着遍历实现 高位在前低位在后 的正确插入顺序 for(int jlen1-1;j0;j--) s(a[i][j]0); //接下来再把s插入字典树 insert(s); } //所有数字二进制插入完成后 //开始遍历每一个数字 然后与字典树进行异或 //如果1有通路就进入1否则进入0 计算最大值 for(int i1;in;i){ int ans0;//存储本轮选中数字与字典树异或的最大值 int p0;//每一轮从字典树根节点开始 string s; for(int jlen1-1;j0;j--){ s(a[i][j]0); } //从最高位往最低位遍历 for(int j0;jlen1;j){ //当s[j]1时 去看对应位数的字典树是否存在通往0路径 if(s[j]1){ //如果0存在 就加上这一位的值 if(tree[p].nxt[0]!0){ anspow(2,len1-j-1); //然后移动指针位置 ptree[p].nxt[0]; } //否则就值不变 移动位置 else ptree[p].nxt[1]; } //当s[j]0时 去看对应位数的字典树是否存在通往1路径 else if(s[j]0){ if(tree[p].nxt[1]!0){ anspow(2,len1-j-1); //然后移动指针位置 ptree[p].nxt[1]; } //否则就值不变 移动位置 else ptree[p].nxt[0]; } } summax(ans,sum); } coutsum; return 0; }版本二位运算写法竞赛标程//前面写法其实常数开销非常大 同时存在pow函数可能的精度问题 //是容易被卡掉的 //下面展示一个精简的位运算写法 运行速度是版本一的数十倍 #include iostream #include algorithm//对应max函数 using namespace std; int n; int a[100010];//原数组直接存十进制整数即可 struct treenode{ int nxt[2]; }tree[4000010]; int pc;//记录当前开辟到了第几个节点 int sum;//异或得到的结果的最大值 //字典树异或查询 int query(int x){ int ans0;//记录x能在字典树内异或得到的最大异或结果 int p0; for(int i30;i0;i--){ //(xi)1是位运算 通过将x右移i位并按位与1 //能够快速精准地提取出x的第i位是0还是1 int y(xi)1; //y^1也是位运算 0变1 1变0 //z就是我们当前这一步希望走进去的相反通道 int zy^1; //如果渴望的相反分支被开辟过存在 if(tree[p].nxt[z]!0){ ans(1i);//异或成功 加上这一位的权重 ptree[p].nxt[z];//走进相反分支 } //如果相反分支是死路 只能走进与自己相同的分支 //异或结果为0 不加分 else ptree[p].nxt[y]; } //走到树底 返回这次异或最大值 return ans; } //字典树插入 void insert(int x){ int p0; //统一从30位向下剥离 确保所有数字都在树上拥有相同长度的路径 for(int i30;i0;i--){ int y(xi)1;//提取当前位 //路径不存在 开辟新节点 if(tree[p].nxt[y]0) tree[p].nxt[y]pc; //下移 ptree[p].nxt[y]; } } int main(){ ios::sync_with_stdio(false); cin.tie(0); cinn; //将每个整数插入字典树 for(int i1;in;i){ cina[i]; insert(a[i]); } //遍历每个数字与字典树进行异或找最大值 for(int i1;in;i){ summax(sum,query(a[i])); } coutsum; return 0; }

相关文章:

【例题2】The XOR Largest Pair(信息学奥赛一本通- P1472)

【题目描述】在给定的 N 个整数 A1,A2,…,AN 中选出两个进行异或运算,得到的结果最大是多少?【输入】第一行一个整数 N。第二行 N 个整数 Ai​​ 。【输出】一个整数表示答案。【输入样例】5 2 9 5 7 0【输出样例】14【提示】对于 100% 的数据&#xff0…...

3分钟解锁Translumo:Windows平台屏幕实时翻译的终极解决方案

3分钟解锁Translumo:Windows平台屏幕实时翻译的终极解决方案 【免费下载链接】Translumo Advanced real-time screen translator for games, hardcoded subtitles in videos, static text and etc. 项目地址: https://gitcode.com/gh_mirrors/tr/Translumo 还…...

CVAT教程

ubuntu服务器部署 https://blog.csdn.net/qq_48187848/article/details/146040443?spm1001.2101.3001.6661.1&utm_mediumdistribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogOpenSearchComplete%7ERate-1-146040443-blog-145734432.235%5Ev43%5Epc_blog_bottom…...

视觉伺服visual servoing

模拟视觉反馈(图像 X/Y 偏差)自动控制机械臂末端向目标移动闭环控制,偏差越小速度越低无硬件相机也能运行(内置虚拟视觉信号)视觉伺服 Visual Servoing 示例代码cpp运行/********************************************…...

20+终极Obsidian模板:简单快速构建你的卡片盒笔记系统

20终极Obsidian模板:简单快速构建你的卡片盒笔记系统 【免费下载链接】Obsidian-Templates A repository containing templates and scripts for #Obsidian to support the #Zettelkasten method for note-taking. 项目地址: https://gitcode.com/gh_mirrors/ob/O…...

Beyond Compare 5密钥生成终极指南:从激活失败到完全使用

Beyond Compare 5密钥生成终极指南:从激活失败到完全使用 【免费下载链接】BCompare_Keygen Keygen for BCompare 5 项目地址: https://gitcode.com/gh_mirrors/bc/BCompare_Keygen 你是否也遇到过Beyond Compare 5弹出"评估模式错误"的困扰&#…...

告别Unity WebGL的模糊UI:用Vue3重构前端界面,手把手教你实现双向通信

Unity WebGL与Vue3的完美联姻:打造高清交互界面的实战指南 1. 为什么需要重构Unity WebGL的UI系统? 许多Unity开发者都曾经历过这样的困境:当我们将精心制作的3D项目发布为WebGL版本时,原生UGUI在浏览器中的表现往往不尽如人意。模…...

零基础转专业计算机机试,我用这5道题帮你摸清浙工大出题套路(附C++代码)

零基础转专业计算机机试:5道真题破解浙工大出题密码(附C实战代码) 第一次面对计算机转专业机试时,我盯着屏幕上闪烁的光标,手指悬在键盘上方却不知从何下手。那种面对陌生题型的茫然感,至今记忆犹新。现在作…...

麒麟KylinOS 2303系统管理员必备:用模板为新用户批量配置统一电源策略

麒麟KylinOS 2303系统管理员实战:批量配置用户电源策略的模板化方案 在企业办公环境或学校机房中,麒麟KylinOS系统管理员经常面临统一管理多台电脑电源策略的需求。传统逐台配置的方式效率低下,而通过/etc/skel/用户模板目录的机制&#xff0…...

保姆级教程:用STM32F103C8T6和MAX485芯片实现稳定的一主多从RS485通讯(附完整代码)

STM32F103C8T6与MAX485构建工业级RS485总线系统实战指南 在工业自动化领域,稳定可靠的通信系统如同神经脉络般重要。想象一下,当您需要在一个大型温室中部署数十个温湿度传感器,或者在一个工厂车间监控多台设备的运行状态时,点对点…...

面试必问:AI 医疗平台怎么设计?这次彻底讲透

AI 医疗平台怎么设计?一次讲清医生辅助、知识库、问答系统与安全边界 大家好,我是一名有 4 年工作经验的 Java 后端开发。 AI 和医疗结合这个方向这两年非常热,但也正因为它太敏感,所以最怕两种极端:一种是把它吹成“万…...

设计饮用水水质饮用习惯监测程序,统计每日饮水量,提醒科学补水养成健康习惯。

饮用水水质与饮水习惯监测程序——基于日志与规则的健康行为实验系统一、实际应用场景描述在现代城市生活中,很多人存在以下问题:- 不清楚自己每天喝了多少水- 饮水时间集中在晚上或运动后- 长期饮水不足或过量- 对水质来源缺乏基本记录意识本项目的目标…...

ScienceDecrypting完整指南:3步永久解锁加密PDF文档限制

ScienceDecrypting完整指南:3步永久解锁加密PDF文档限制 【免费下载链接】ScienceDecrypting 破解CAJViewer带有效期的文档,支持破解科学文库、标准全文数据库下载的文档。无损破解,保留文字和目录,解除有效期限制。 项目地址: …...

Java 面试高频题:通知平台整体架构一般怎么拆?

消息实时通知平台架构总览怎么搭?一次讲清渠道、模板、推送、回执、偏好与治理闭环 大家好,我是一名有 4 年工作经验的 Java 后端开发。 从第129天开始,我连续围绕消息实时通知系统写了整体设计、渠道抽象、模板中心、实时推送、异步投递、偏…...

openCode 是什么?你电脑里常驻的 AI 开发搭档

凌晨一点,你正在改一个棘手的 Bug。 控制台里报错信息刷了一屏,你盯着那段陌生的代码——是上周同事写的,没注释,没文档。你下意识选中代码,复制,打开浏览器,粘贴到 ChatGPT 的对话框里。 等等。…...

全面战争模组制作新纪元:RPFM工具让你的创意无限延伸

全面战争模组制作新纪元:RPFM工具让你的创意无限延伸 【免费下载链接】rpfm Rusted PackFile Manager (RPFM) is a... reimplementation in Rust and Qt6 of PackFile Manager (PFM), one of the best modding tools for Total War Games. 项目地址: https://gitc…...

VisDrone2019数据集转换COCO格式实战:手把手教你用Python脚本搞定YOLOX训练数据准备

VisDrone2019数据集转换COCO格式全流程解析:从数据清洗到YOLOX适配 无人机视角下的目标检测一直是计算机视觉领域的特殊挑战。VisDrone2019作为该领域最具代表性的开源数据集,包含了10个类别、超过26万张标注图像,但原始数据格式与主流框架的…...

从膨胀腐蚀到Hough变换:图像处理面试官最爱问的10个核心概念,一次讲透

从膨胀腐蚀到Hough变换:图像处理面试官最爱问的10个核心概念,一次讲透 在计算机视觉和图像处理领域的技术面试中,某些核心概念几乎成为必考题。这些概念不仅是理论基础,更是实际项目中的常见工具。本文将深入解析面试中最常被问及…...

不止于获取数据:用baostock+Pandas+Matplotlib打造你的第一个股票分析仪表盘

从数据获取到洞察生成:构建股票分析仪表盘的全流程实战 在金融数据分析领域,获取原始数据只是万里长征的第一步。真正有价值的是如何将这些数据转化为可操作的洞察。本文将带你使用Python生态中的baostock、Pandas和Matplotlib等工具,构建一个…...

YOLOv8在Jetson上导出TensorRT引擎(.engine)全流程实操:从ONNX转换到INT8/FP16量化加速

YOLOv8在Jetson平台上的TensorRT引擎部署与量化加速实战指南 当目标检测模型需要部署到边缘计算设备时,性能优化往往成为最关键的技术挑战。本文将深入探讨如何将YOLOv8模型高效转换为Jetson平台专用的TensorRT引擎,并通过INT8/FP16量化技术实现推理速度…...

XC7Z010-2CLG400I Xilinx Zynq-7000 FPGA

XC7Z010-2CLG400I 可以理解为一颗“ARM 处理器 FPGA 可编程逻辑”合在一起的 SoC。它属于 Xilinx (赛灵思 AMD )Zynq-7000 家族里的 Z-7010 器件,核心特点就是把 双核 Arm Cortex-A9 MPCore 处理系统(PS) 和 7 系列可编程逻辑&am…...

别再死磕流程图了!用PAD图搞定详细设计,代码自动生成不是梦

别再死磕流程图了!用PAD图搞定详细设计,代码自动生成不是梦 如果你还在用传统流程图做详细设计,每次修改需求都要重画半张图;如果你受够了N-S图方框套方框的视觉折磨,连个简单循环都要画成俄罗斯套娃——是时候认识PAD…...

终极Visual C++运行库修复指南:如何一次性解决所有DLL缺失问题

终极Visual C运行库修复指南:如何一次性解决所有DLL缺失问题 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾因"找不到MSVCP140.dll&qu…...

meituan 民宿 mtgsig1.2

声明 本文章中所有内容仅供学习交流使用,不用于其他任何目的,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!逆向分析cp execjs.compile(open(民宿-…...

LLaMA论文里的三个关键技术点:SwiGLU、RoPE和RMSNorm,到底在解决什么问题?

LLaMA架构三大核心技术解析:SwiGLU、RoPE与RMSNorm的工程智慧 当ChatGPT掀起大模型浪潮时,Meta开源的LLaMA系列却以更小的参数量展现出惊人性能。这背后离不开三个关键技术点的精妙设计:SwiGLU激活函数、旋转位置编码(RoPE)和RMSNorm层归一化…...

数据库备份与恢复策略

数据库备份与恢复策略 1. 技术分析 1.1 备份概述 备份是数据安全的基石: 备份类型完全备份: 全部数据增量备份: 变化数据差异备份: 上次完全备份后的变化备份策略:定期完全备份增量备份补充实时备份1.2 恢复策略 恢复类型完全恢复: 恢复到最新状态时间点恢复: 恢复到…...

从AstraPro深度相机到机械臂抓取:ROS2三维手眼标定全流程实战(含D2C配准)

从AstraPro深度相机到机械臂抓取:ROS2三维手眼标定全流程实战 在工业自动化和机器人研究领域,三维手眼标定是实现精准视觉引导操作的核心技术。当我们需要让机械臂在复杂环境中自主完成分拣、装配或检测任务时,如何确保相机"看到"的…...

D3KeyHelper:暗黑3终极宏工具完整指南 - 5分钟快速上手

D3KeyHelper:暗黑3终极宏工具完整指南 - 5分钟快速上手 【免费下载链接】D3keyHelper D3KeyHelper是一个有图形界面,可自定义配置的暗黑3鼠标宏工具。 项目地址: https://gitcode.com/gh_mirrors/d3/D3keyHelper D3KeyHelper是一款专为《暗黑破坏…...

更全面的 Token 套餐来了:Agent Plan

作为一名 Token 消耗大户,各模型厂商和云厂商的套餐我基本都有入手:智谱、MiniMax、小米 Mimo,以及最早推出 Coding Plan 的火山引擎,这些都是我目前在订的。以前 Coding Plan 基本能够覆盖日常工作,但是随着越来越多场…...

别再手动拼接数据了!用ONNXRuntime和TensorRT实现多Batch推理的Python/C++实战对比

多Batch推理实战:ONNXRuntime与TensorRT的高效对决 在计算机视觉项目的实际部署中,我们常常会遇到这样的场景:摄像头持续采集图像,或者需要同时处理来自多个传感器的数据。如果每次只处理单张图片,就像用吸管喝一大桶…...