首页 > 其他分享 >异或值

异或值

时间:2023-03-05 20:55:06浏览次数:39  
标签:int max tr 29 leq 异或

异或值

给定一个长度为 $n$ 的整数序列 $a_1,a_2, \ldots, a_n$。

请你找到一个非负整数 $X$,使得 $\max\limits_{1 \leq i \leq n} \{ a_i \oplus X \}$ 的值尽可能小,其中 $\oplus$ 表示按位异或。

输出 $\max\limits_{1 \leq i \leq n} \{ a_i \oplus X \}$ 的最小可能值。

输入格式

第一行包含整数 $n$。

第二行包含 $n$ 个整数 $a_1,a_2,\ldots,a_n$。

输出格式

一个整数,表示 $\max\limits_{1 \leq i \leq n} \{ a_i \oplus X \}$ 的最小可能值。

数据范围

前 $3$ 个测试点满足 $1 \leq n \leq 3$。
所有测试点满足 $1 \leq n \leq {10}^{5}$,$0 \leq a_i \leq {2}^{30}−1$。

输入样例1:

3
1 2 3

输出样例1:

2

输入样例2:

2
1 5

输出样例2:

4

 

解题思路

  先把每个数的二进制表示用Trie存下来,然后在Trie上dfs求异或结果的最小值。

  从二进制的最高位(第$29$位)开始看,$X$的最高位有两种选择,即$0$和$1$。由于异或运算对每个位是独立的,我们可以先递归求出两棵子树(即$0$和$1$两个方向)在第$28$位到第$0$位中异或结果的最大值的最小值,假设存在且为$a$(对应$0$那个分支的子树)和$b$(对应$1$那个分支的子树)。如果$X$的最高位是$0$,那么异或结果的最大值的最小值就是$\max \{ a, b + 2^{29} \}$。同理如果$X$的最高位是$1$,那么异或结果的最大值的最小值就是$\max \{ a + 2^{29}, b \}$。最终的答案就是这两种情况的最小值,即$\min \left\{ \max \{ a, b + 2^{29} \}, \ \max \{ a + 2^{29}, b \} \right\}$。

  更一般的,如果递归到$X$的第$d$位,那么第$d$位到第$0$位的异或结果的最大值的最小值就是$$\min \left\{ \max \{ a, b + 2^{d} \}, \ \max \{ a + 2^{d}, b \} \right\}$$

  其中如果$0$对应的那个分支不存在,那么令$a = -\infty$。如果$1$对应的那个分支不存在,那么令$b = -\infty$。

  然后是时间复杂度的问题,看上去好像每层递归都有两个分支,时间复杂度为$O(2^{30})$。实则不然,因为Trie中最多只有$30 \times n$个节点,因此时间复杂度应该是$O(30 \times n)$。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 30e5 + 10;
 5 
 6 int tr[N][2], idx;
 7 
 8 void insert(int x) {
 9     int p = 0;
10     for (int i = 29; i >= 0; i--) {
11         int t = x >> i & 1;
12         if (!tr[p][t]) tr[p][t] = ++idx;
13         p = tr[p][t];
14     }
15 }
16 
17 int dfs(int u, int d) {
18     if (d == -1) return 0;
19     int a = -2e9, b = -2e9;
20     if (tr[u][0]) a = dfs(tr[u][0], d - 1);
21     if (tr[u][1]) b = dfs(tr[u][1], d - 1);
22     return min(max(a, b + (1 << d)), max(a + (1 << d), b));
23 }
24 
25 int main() {
26     int n;
27     scanf("%d", &n);
28     while (n--) {
29         int x;
30         scanf("%d", &x);
31         insert(x);
32     }
33     printf("%d", dfs(0, 29));
34     
35     return 0;
36 }

 

参考资料

  AcWing 4869. 异或值(AcWing杯 - 周赛):https://www.acwing.com/video/4644/

标签:int,max,tr,29,leq,异或
From: https://www.cnblogs.com/onlyblues/p/17181584.html

相关文章

  • lg7335 [JRKSJ R1] 异或 题解
    本题的标签中含有trie,但是这道题可以不用trie做。考虑列出本题的dp方程:设\(f_{k,i}\)表示前\(i\)个数选了\(k\)段的答案,\(s_i\)为数组的前缀异或和当不选择第\(i\)位,使用......
  • trie 树 求最大异或和
    题目:给定一个非负整数数列a,初始长度为N。请在所有长度不超过M的连续子数组中,找出子数组异或和的最大值。子数组的异或和即为子数组中所有元素按位异或得到的结果。......
  • leetcode 2564. 子字符串异或查询[题解]
    链接:子字符串异或查询思路:题目说\(val\oplusfirst=second\)可得\(val=second\oplusfirst\)题目变成从\(0-1\)串中找到最先出现的\(val\)的二进制表示,注意是\(10^......
  • #10051. 「一本通 2.3 例 3」Nikitosh 和异或
    求两段不相交子序列,他们异或和的和最大  #include<iostream>#include<algorithm>#include<cstring>usingnamespacestd;constintN=4e5+4;intch[N*32......
  • 最大异或和
    #include<bits/stdc++.h>usingnamespacestd;constintN=1e5+10,M=N*31;intn,m;intidx,ch[M][2],cnt[M];ints[N];intans;voidinsert(intx,intv)//通过......
  • 2、异或运算
    1、按位异或运算^按位异或(^):相同为0,不同为1;按位异或(^):相当于无进位相加例如:01010^01101=00111特性:任何数异或上0等于其本身:0^n=n两个相同的数异或为0:n^......
  • Verilog之异或^的应用
    异或:相同为0,不同为1。 一、可用于两个整数的值进行交换,不用借助第三个变量。若a=5(0101),b=10(1010)经以下变换,可完成值的交换:a=a^b;0101^1010=1111b=b^a;10......
  • Verilog之异或^的应用
    一、用于两个整数的值进行交换,不用借助第三个变量。若a=5(0101),b=10(1010)经以下变换,可完成值的交换:a=a^b;0101^1010=1111b=b^a;1010^1111=0101a=a^b; 1......
  • 异或1的妙处
    异或1的妙处刷lc每日一题时,看评论发现一种异或1的解法,感觉很有趣就研究了一下。题目如下:给你一个下标从0开始的整数数组nums。在一步操作中,你可以执行以下步骤:从n......
  • 【算法题--异或操作】找出数组中唯一没有重复的那个元素
    在我的博客上有一篇博文是提到C#里面的异或操作https://www.cnblogs.com/wphl-27/p/17104240.html有一个算法题是需要用到C#中的异或操作的,这道算法题就是获取一个数组中......