# [AcWing143] 最大异或和 [字典树]

[AcWing143] 最大异或和 [字典树]

传送门

题意

给出N个整数,选择两个整数,使得异或和最大(\(0<A_i<2^{31}\))

思路

从数据范围很容易想到二进制,进而想到字典树Trie。

字典树的典型应用是存储字符串,存储二进制也是一样的。

我一开始在处理取二进制位的时候想的比较麻烦,我是使用右移运算符先预处理出每个数的二进制表示,再根据二进制表示插入字典树中。后来了解到x >> i & 1;可以直接取二进制数的任意一位,这样简单了许多。

查询的时候,先取出对应位的二进制数,在树中先走该二进制数的对立面,如果对立面不存在,再沿着该二进制数向下走一层。

Code:

#include <bits/stdc++.h>
using namespace std;
#define fre freopen("data.in","r",stdin);
#define ms(a) memset((a),0,sizeof(a))
#define go(i,a,b) for(register int (i)=(a);(i)<(b);++(i))
#define rep(i,a,b) for(register int (i)=(a);(i)<=(b);++(i))
#define sf(x) scanf("%d",&(x))
#define reg register
typedef long long LL;
const int inf=(0x3f3f3f3f);
const int maxn=1e5+5;
int a[maxn],son[maxn*31][2],idx;
int n;
inline void insert(int x){
    int p=0,t;
    for(int i=30;i>=0;i--){
        t= x >> i & 1; //取二进制数的第i位,从0开始
        if(!son[p][t])son[p][t]=++idx;
        p=son[p][t];
    }
}
inline int query(int x){
    int ans=0,t,p=0;
    for(int i=30;i>=0;--i){
        t=x>>i&1;
        if(son[p][!t]){
            p=son[p][!t];
            ans|=(1<<i);
        }
        else {
            p=son[p][t];
        }
    }
    return ans;
}
int main(){
    sf(n);
    rep(i,1,n){
        sf(a[i]);
        insert(a[i]);
    }
    int mx=-1;
    rep(i,1,n){
        mx=max(mx,query(a[i]));
    }
    printf("%d",mx);
    return 0;
}

原文地址:https://www.cnblogs.com/sstealer/p/12233116.html

时间: 2024-07-29 19:50:57

# [AcWing143] 最大异或和 [字典树]的相关文章

hdu5269 ZYB loves Xor I 异或,字典树

hdu5269  ZYB loves Xor I   异或,字典树 ZYB loves Xor I Accepts: 142 Submissions: 696 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) 问题描述 ZYB喜欢研究Xor,现在他得到了一个长度为nn的数组A.于是他想知道:对于所有数对(i,j)(i \in [1,n],j \in [1,n])(i,j)(i∈[1,n

关于异或_字典树的一些性质

异或的性质 1. a ⊕ a = 0 2. a ⊕ b = b ⊕ a 3. a ⊕b ⊕ c = a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c; 4. d = a ⊕ b ⊕ c 可以推出 a = d ⊕ b ⊕ c. 5. a ⊕ b ⊕ a = b.     自反性 6.若x是二进制数0101,y是二进制数1011: 则x⊕y=1110 只有在两个比较的位不同时其结果是1,否则结果为0 即"两个输入相同时为0,不同则为1"! 字典树:又称为Trie,是一种用于快速检索的多叉

NEUOJ711 异星工厂 字典树+贪心

题意:你可以收集两个不相交区间的权值,区间权值是区间异或,问这两个权值和最大是多少 分析:很多有关异或求最大的题都是利用01字典树进行贪心,做这个题的时候我都忘了...最后是看别人代码的时候才想起来这个套路 l[i],记录,从 1 到 i  里 最大的异或区间权值, r[i], 记录,从  i 到 n 里 最大的异或区间权值 这样两轮插入,然后查询贪心就行了,插入的是前缀和后缀的异或2进制序列,从大的开始(贪心) 注:吐槽,其实都是套路,异或和求最大,往往要利用字典树进行贪心 #include

POJ 3764 The xor-longest Path 字典树求最大异或

题意,一颗树,每个边有个值,在树上找一条简单路径,使得这条路径上的边权异或值最大 把这题模型转换一下, 对于任意一条路径的异或,表示为f(u, v) 则f(u, v) = f(1, u) ^ f(1, v) 这是显然的 其中f(1, i)是可以再O(n)内处理出来 然后就是在一个数组内,找两个数异或值最大 然后就可以用字典树来搞 每个数变成01串,  然后插入字典树, 第30位在最前,然后29,依次到0位 就建立成了一个深度为31的字典树 对于一个询问,在字典树上找,就是尽量找跟其相反的路径.

[01字典树]求序列完美度(求区间最大异或值)

https://nanti.jisuanke.com/t/15531 解题关键:01字典树模板,用字典树保存每个数的二进制表示,从而动态维护区间上的最大异或值,注意添加和删除都可以用于一个change函数表示. 复杂度:$O(n\log n + {n^2}\log n)$ 1 #include<bits/stdc++.h> 2 #define maxn 1005 3 #define inf 0x3f3f3f3f 4 using namespace std; 5 typedef long lon

Chip Factory---hdu5536(异或值最大,01字典树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5536 题意:有一个数组a[], 包含n个数,从n个数中找到三个数使得 (a[i]+a[j])⊕a[k]最大,i,j,k不同; 求异或的结果最大所以我们可以用01字典树,先把所有的数加入字典树中,从n个数中选出两个数a[i]和a[j], 先把他们从字典树中删除,然后找到与a[i]+a[j]异或最大的数,和结果取最大值即可: 最后不要忘记再把a[i]和a[j]添加到字典树中即可: #include<st

2014百度之星第三题Xor Sum(字典树+异或运算)

Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Total Submission(s): 4445    Accepted Submission(s): 652 Problem Description Zeus 和 Prometheus 做了一个游戏.Prometheus 给 Zeus 一个集合,集合中包括了N个正整数.随后 Prometheus 将向 Ze

POJ 3764 (异或+字典树)

早就听过用字典树求异或最大值,然而没做过.发现一碰到异或的题就GG,而且因为以前做过的一道类似的题(事实上并不类似)限制了思路,蠢啊= =. 题意:一棵带权的树,求任意两点间路径异或的最大值. 题解:设xor(a,b)是求a,b间路径的异或值,那么xor(a,b)=xor(root,a)^xor(root,b).因为如果LCA(a,b)==root时结论显然成立,不然的话就会有重复走过的部分,但是异或有性质x^x=0,所以LCA(a,b)!=root结论依然成立. 这样题目就很简单了.对每一个x

POJ 3764 The xor-longest Path ( 字典树应用—— 求连续段相异或最大最小的线性算法)(好题)

题意:已知:给出n个结点的树,定义:两结点间的权值为两点之间所有边相异或的值.求:树中的某两点间的最大权值. 思路:先说简单一点的题:有道CowXor,是一串线性序列,求某连续段异或的最大值,这题的思路是先求前i项序列相异或的值Si,所以x到y的连续异或就是Sx^Sy ,因为a^b = (a ^ c) ^ (b ^ c). 这题同样是这个思路把线性拓展到树上,先求任何点到某一定点的连续异或值,比如选根结点0,所以这时候有两种情况,1.x,y的路径通过了根结点,显然正确.2.x,y的路径不通过根结