如果你觉得这篇题解对你有用,可以点个赞或关注再走呗,谢谢你的关注~## 不清楚蓝桥杯考什么的点点下方👇
考点秘籍
想背纯享模版的伙伴们点点下方👇
蓝桥杯省一你一定不能错过的模板大全(第一期)
蓝桥杯省一你一定不能错过的模板大全(第二期)
蓝桥杯省一你一定不能错过的模板大全(第三期)
蓝桥杯省一你一定不能错过的模板大全(第四期)!!!
想背注释模版的伙伴们点点下方👇
蓝桥杯必背第一期
蓝桥杯必背第二期
往期精彩回顾
蓝桥杯上岸每日N题 第一期(一)!!!
蓝桥杯上岸每日N题第一期(二)!!!
蓝桥杯上岸每日N题第一期(三)!!!
蓝桥杯上岸每日N题第二期(一)!!!
蓝桥杯上岸每日N题第三期(一)!!!
蓝桥杯上岸每日N题 第四期(最少刷题数)!!!
蓝桥杯上岸每日N题 第五期(山)!!!
蓝桥杯上岸每日N题 第六期(求阶乘)!!!
蓝桥杯上岸每日N题 第七期(小猫爬山)!!!
蓝桥杯上岸每日N题 第八期 (全球变暖)!!!
操作系统期末题库 第九期(完结)
LeetCode Hot100 刷题(第三期)
idea创建SpringBoot项目报错解决方案
数据库SQL语句(期末冲刺)
想看JavaB组填空题的伙伴们点点下方 👇
填空题
竞赛干货
算法竞赛字符串常用操作大全
蓝桥杯上岸必刷!!!(模拟/枚举专题)
蓝桥杯上岸必背!!! (第三期 DP)
蓝桥杯上岸必背!!!(第四期DFS)
蓝桥杯上岸必背!!!(第五期BFS)
蓝桥杯上岸必背!!!(第六期树与图的遍历)
蓝桥杯上岸必背!!!(第七期 最短路算法)
蓝桥杯上岸必背!!!(第八期 简单数论)
蓝桥杯上岸必刷!!!(进制、数位专题)
蓝桥杯上岸考点清单 (冲刺版)!!!
分析
最大异或对
(1)最大异或对是运用trie树存储十进制数对应的二进制数的每一位。
(2)再根据trie树的每一位进行搜索查找,严格满足不同的数异或为1,相同的异或为0。
(3)根据(2)进行搜索,从最高位开始搜索,尽可能地保证较高位次的异或数最大。
通过搜索,匹配每个位最大的异或数。
即从最高位开始,尽可能多地保证每一位的异或数为1,要保证这一点,就需要往当前位数不同的方向走,这样所得到的结果最大。
换句话来说,从最高位开始,往当前位数不同的方向走,如0往1,1往0的方向走,实在无不同位数就走相同位数。
trie结果唯一 及 确保选取两个数
query
一个数的时候,这时该数会根据之前插进trie
树的每个数的二进制数进行搜索,直至搜到叶子节点,结果唯一,那这样就保证我们是选择了两个数去进行异或操作,最后得到唯一的最大值。
注意!
理论上,先插入再查找和先查找再插入均可。
但在实现时,考虑到边界问题,即最开始树为空时,查找的边界问题。
采用先插入再查找的方式实现,trie数左节点为0
,右节点为1
。
分析图
模拟
res+=1<<i
注:把异或数为1
的数位左移1
相当于2
的i
次方,再把每次枚举的每个位置的结果加起来,就可以得出最大值。
trie树在数组的体现
ACcode
import java.io.*;
public class Main{
static int N=3100010;
//总共是10000个数,每个数枚举对应二进制数的30个位置
//所以总共是31000010个数
//数组开小的话为MLE
static int idx;
static int son[][]=new int [N][2];
//一定要记得是0\1两列 p到0和p到1
public static void insert(int x){
int p=0;
for(int i=30;i>=0;i--){
int u=x>>i&1;
if(son[p][u]==0)son[p][u]=++idx;
p=son[p][u];
}
}
public static int query(int x){
int p=0,res=0;
for(int i=30;i>=0;i--){
int u=x>>i&1;
if(son[p][1-u]!=0){
res+=1<<i;
p=son[p][1-u];
}
else{
p=son[p][u];
}
}
return res;
}
public static void main(String []args)throws IOException{
BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw=new PrintWriter(new OutputStreamWriter(System.out));
String str[]=bf.readLine().split(" ");
int n=Integer.parseInt(str[0]);
String s[]=bf.readLine().split(" ");
for(int i=0;i<n;i++)
{
insert(Integer.parseInt(s[i]));
}
int res=0;
for(int i=0;i<n;i++){
int t=query(Integer.parseInt(s[i]));
res=Math.max(res,t);
}
pw.println(res);
pw.flush();
}
}
详解代码
import java.io.*;
public class Main{
static int N=3100010;
static int idx;
static int son[][]=new int [N][2];
public static void main(String []args)throws IOException{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
int n = Integer.parseInt(in.readLine());
String s[]=in.readLine().split(" ");
for(int i=0;i<n;i++){
insert(Integer.parseInt(s[i]));
}
int res=0;
for(int i=0;i<n;i++){
int t = query(Integer.parseInt(s[i]));
res=Math.max(res,t);
}
out.write(res+" ");
out.close();
}
public static void insert(int x){
int p=0;
for(int i=30;i>=0;i--){
int u=x>>i&1;//取出二进制数的第i位
if(son[p][u]==0)son[p][u]=++idx;//如果还未被创建,则进行建边操作,连接两个节点,即++idx
p=son[p][u];//往下一层走
}
}
public static int query(int x){
int p=0,res=0;
for(int i=30;i>=0;i--){
int u=x>>i&1;
if(son[p][1-u]!=0){
//当u=0时,即1-0=1,往1的方向走,异或值最大。
//son[p][1-u]用来确定1方向的
//点是否存在,存在则进行下面操作
//不存在则只能选择唯一的路来走
//当u=1时,即1-1=0,往0的方向走,异或值最大。
//son[p][1-u]用来确定1方向的点是否存在,存在则进行下面操作
//不存在则只能选择唯一的路来走
res+= 1<<i;//1<<i = 1 *2的i次方
//if分支内得到的异或数为1,加上。
//else分支内得到的异或数为0,不需要加上。
p=son[p][1-u];//以此进入下一层
}
else{
//只能选择下面唯一的路来做
p=son[p][u];
}
}
return res;
}
}