1 条题解
-
0
自动搬运
来自洛谷,原作者为

Atserckcn
愿你的刀仍然锋利搬运于
2025-08-24 22:58:16,当前版本为作者最后更新于2024-06-07 23:26:28,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
P10471 最大异或对 The XOR Largest Pair 题解
题目简述:
共给你 个整数,其中任选两数进行异或运算,求最大值。
分析算法:
1、枚举
时间复杂度: ,直接排除,OUT。
2、运用字典树进行枚举,具体方法在后面。
知识点梳理:
1、异或:两个数进行按位异或运算,相同为 ,不相同为 。
2、字典树:
字典树(trie 树)是一种用于实现字符串快速检索的多叉树结构。
trie 树的每个节点都拥有若干个字符指针,若在插入或检索字符串时扫描到一个字符 c,就沿着当前节点的 c 字符指针,走向该指针指向的节点。
思路分析:
上文提到,用枚举肯定超时。
考虑运用字典树对其进行优化。
优化方法:
把每一个数字转换成二进制的 字符串插入字典树,再依次遍历整棵字典树。
遍历的时候我们该注意什么?该选择哪一条分支遍历下去?
选择:因为异或运算是相同为 ,不相同为 ,所以我们考虑贪心,即这一位尽量为 。
给一个更直观的图片,以下即为字典树,存储的是数字 、、、:(别忘了二进制转化)。

晚上11点临时画的,画技不好勿喷代码实现:
字典树的代码实现:
struct EDGE{//结构体存字典树 ll son[2]; }node[MAXN];没错,就这么简单。
node[p].son[t]表示在字典树的 号节点的第 个分支( 为 或 )。将一个数字插入操作:
void insert(ll num)//插入数字num { now=0; for(int i=31;i>=0;i--)//一定是i>=0!!不是i;(血泪的教训,调到了晚上11点) { t=(num>>i)&1;//取该位 if(!node[now].son[t]) node[now].son[t]=++cnt;//创建新的字典树节点 now=node[now].son[t];//更新现在所处的节点 } return; }查询操作:
ll find(ll num)//查询数字num { ans=now=0; for(int i=31;i>=0;i--)//一定是i>=0!!不是i;(血泪的教训,调到了晚上11点) { t=(num>>i)&1; if(!node[now].son[t^1]) now=node[now].son[t]; else { now=node[now].son[t^1]; ans=ans^(1<<i); } } return ans; }好啦,接下来主函数很简单的,直接上完整代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll n,sum,ans,now; bool t; const int MAXN=1e7+5; ll a[MAXN]; struct EDGE{//结构体存字典树 ll son[2]; }node[MAXN]; ll cnt; inline void read(ll &num)//快读,不会的同学可忽略 { char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') num=-num; ch=getchar(); } while(ch>='0'&&ch<='9') { num=(num<<1)+(num<<3)+(ch-'0'); ch=getchar(); } return; } void insert(ll num)//插入数字num { now=0; for(int i=31;i>=0;i--)//一定是i>=0!!不是i;(血泪的教训,调到了晚上11点) { t=(num>>i)&1; if(!node[now].son[t]) node[now].son[t]=++cnt;//创建新的字典树节点 now=node[now].son[t];//更新现在所处的节点 } return; } ll find(ll num)//查询数字num { ans=now=0; for(int i=31;i>=0;i--)//一定是i>=0!!不是i;(血泪的教训,调到了晚上11点) { t=(num>>i)&1; if(!node[now].son[t^1]) now=node[now].son[t]; else { now=node[now].son[t^1]; ans=ans^(1<<i); } } return ans; } int main(){ read(n); for(int i=1;i<=n;i++) { read(a[i]); insert(a[i]); } for(int i=1;i<=n;i++) sum=max(sum,find(a[i]));//打擂台 printf("%lld\n",sum); return 0; }附:如果你会了本题,建议去做双倍经验P4551 最长异或路径
- 1
信息
- ID
- 10170
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者