异或值

异或值

给定一个长度为 n 的整数序列 a1,a2,,an

请你找到一个非负整数 X,使得 max1in{aiX} 的值尽可能小,其中 表示按位异或。

输出 max1in{aiX} 的最小可能值。

输入格式

第一行包含整数 n

第二行包含 n 个整数 a1,a2,,an

输出格式

一个整数,表示 max1in{aiX} 的最小可能值。

数据范围

3 个测试点满足 1n3
所有测试点满足 1n1050ai2301

输入样例1:

3
1 2 3

输出样例1:

2

输入样例2:

2
1 5

输出样例2:

4

 

解题思路

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

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

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

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

  然后是时间复杂度的问题,看上去好像每层递归都有两个分支,时间复杂度为O(230)。实则不然,因为Trie中最多只有30×n个节点,因此时间复杂度应该是O(30×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/

posted @   onlyblues  阅读(101)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
历史上的今天:
2022-03-05 聪明的燕姿
Web Analytics
点击右上角即可分享
微信分享提示