最大异或对

题目传送:https://www.acwing.com/problem/content/description/145/

在给定的N个整数A1,A2……AN<?XML:NAMESPACE PREFIX = "[default] http://www.w3.org/1998/Math/MathML" NS = "http://www.w3.org/1998/Math/MathML" />A1,A2……AN中选出两个进行xor(异或)运算,得到的结果最大是多少?

输入格式

第一行输入一个整数N。

第二行输入N个整数A1A1~ANAN。

输出格式

输出一个整数表示答案。

数据范围

1≤N≤1051≤N≤105,
0≤Ai<2310≤Ai<231

输入样例:
3
1 2 3
输出样例:
3

暴力是最简单的解题办法。这题先拿暴力来写。
  1 #include <iostream>
  2 #include <algorithm>
  3 using namespace std;
  4 const int N = 1e6 + 5;
  5 int a[N];
  6 
  7 int main() {
  8 	int n;
  9 	cin >> n;
 10 	for(int i = 0; i < n; ++ i)
 11 		cin >> a[i];
 12 	int res = 0;
 13 	for(int i = 0; i < n; ++ i)
 14 		for(int j = 0; j < n; ++ j)
 15 			if(i != j)
 16 				res = max(res, a[i]^a[j]);
 17 	cout << res << endl;
 18 	return 0;
 19 }


这种方法往往是,会带来完美的TLE。当然优化的方法就要通过观察,可以通过什么数据结构将复杂度降下来。

先观察暴力做法,循环的第一次是没法优化的,观察第二层循环,重复多次求最大值,这显然不是最优的。

先来了解异或,当两个二进制对应位上的值都不相同时就异或值就会最大。

这样看来我们只需要只找它与枚举的数,的二进制尽可能相反。在众多的数据结构中,字典树可以满足这个要求。

我们把每位数都当成32位二进制数,不够的补0.然后通过策略,每次都取对应位相反的数,否子取相同的。

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <string>
  4 using namespace std;
  5 const int N = 1e5 + 5, M = 31 * N;
  6 
  7 int n;
  8 int a[N];
  9 int trie[M][2], tot;
 10 
 11 void insert(int x) { // 通过每个数的二进制来构建字典树,每个节点就只有两个指针 
 12 	int p = 0;
 13 	for (int i = 31; i >= 0; -- i)
 14 	{
 15 		int u = x >> i&1;//取对应的位置的数 
 16 		if(!trie[p][u]) trie[p][u] = ++ tot;
 17 		p = trie[p][u];
 18 	}
 19 }
 20 
 21 int query(int x) {
 22 	int p = 0, res = 0;
 23 	for(int i = 31; i >= 0; -- i) {//每个数都当成二进制位,存储 
 24 		int u = x >> i & 1;
 25 		if(trie[p][!u])//最优策略是走相反的路。 
 26 		{
 27 			p = trie[p][!u];
 28 			res = res*2 + 1;//对应位置相反,则res*2 + 1就相当于0-1 -> 1 ,*2相当于向左移动一位。 
 29 		}
 30 		else {
 31 			p = trie[p][u];// 
 32 			res = res * 2 + 0;
 33 		}
 34 	}
 35 	return res;
 36 }
 37 
 38 int main() {
 39 	cin >> n;
 40 	for(int i = 0; i < n; ++ i)
 41 	{
 42 		cin >> a[i];
 43 		insert(a[i]);
 44 	}
 45 
 46 	int res = 0;
 47 	for(int i = 0; i < n; ++ i) {
 48 		res = max(res, query(a[i]));
 49 	}
 50 	cout << res << endl;
 51 	return 0;
 52 }
posted @ 2020-07-24 18:31  ACWink  阅读(159)  评论(0编辑  收藏  举报