在给定的N个整数A1,A2……ANA1,A2……AN中选出两个进行xor(异或)运算,得到的结果最大是多少?
输入格式
第一行输入一个整数N。
第二行输入N个整数A1A1~ANAN。
输出格式
输出一个整数表示答案。
数据范围
1≤N≤1051≤N≤105,
0≤Ai<2310≤Ai<231
输入样例:
3
1 2 3
输出样例:
3
思路:
我们首先运用暴力将我们的基本思路表达清楚:
#include<iostream> #include<algorithm> using namespace std; const int N = 100010; int a[N]; int main() { int n,res=0; cin >> n; for (int i = 0;i < n; i++) cin >> a[i]; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) res = max(res, a[i] ^ a[j]); cout << res << endl; return 0; }
接下来我们优化这个程序,我们从数据范围可以看出,时间复杂度应该是在nlogn 或者 O(n)的,所以我们估计只需减少一重循环就可以AC掉这个题目。
我们考虑一下第二重循环的意义是什么,然后优化这个代码。这个第二重循环的作用是:a[i]不变时,遍历所有a[j],取最大,这时候我们就要想了,是不是有一些过程是没必要的呢?
我们回顾一下异或运算, 1 ^ 1 = 0 , 0 ^ 0 = 0, 1 ^ 0 = 1,所以我们可以看出,只有二进制中数不同的才能得到最大值,又多了一个限制条件意味这我们距离成功又进了一步。
要依次比对的话,就得将我们的数转化为二进制存储,存储和遍历字符串数值的最高效的方法就是Trie算法。
代码:
#include<iostream> #include<algorithm> using namespace std; const int N = 100010, M = 3000010; int a[N], son[M][2], idx; void insert(int x) {//建立一个树 int p = 0; for (int i = 30; ~i; i--) { int& s = son[p][x >> i & 1]; if (!s) s = ++idx; p = s; } } int query(int x) {//遍历一个树 int p = 0,res = 0; for (int i = 30; ~i; i--) { int s = x >> i & 1; if (son[p][!s]) { res += 1 << i; p = son[p][!s]; } else p = son[p][s]; } return res; } int main() { int n, x, res = 0; cin >> n; for (int i = 0;i < n; i++) cin >> a[i],insert(a[i]); for (int i = 0; i < n; i++) res = max(res, query(a[i])); cout << res << endl; return 0; }
熟悉一下Tries算法:https://www.cnblogs.com/Attacking-vincent/p/13038496.html