acwing 143. 最大异或对
今回是Jill镇楼,
今天题目还是感觉很有意思的,我推荐大家都做,做对了就做爽了(
题干:
在给定的 NN 个整数 A1,A2……ANA1,A2……AN 中选出两个进行 xorxor(异或)运算,得到的结果最大是多少?
输入格式
第一行输入一个整数 NN。
第二行输入 NN 个整数 A1A1~ANAN。
输出格式
输出一个整数表示答案。
数据范围
1≤N≤1051≤N≤105,
0≤Ai<2310≤Ai<231
输入样例:
3
1 2 3
输出样例:
3
暴力我们就不解释了,一个个对比是O(n^2),复杂度爆了。
我们看题目要求异或值,自然会想到二进制。
假设我们有一个图,图上有所有给出数的二进制表示,
我们如何给出关于一个数的最大异或值?
我们只要找每一个对应二进制位数尽量相反(位数从高到低选取),就能保证有最大异或值。
如果我们找n个数的任意两个数最大的异或值,最坏只有O(n*32);
自然会想到只有零一的左右儿子的二叉树,我们一建树,一看题目,空间爆了(
我们然后就会想到用字典数的建树方法来建这个只有零一的二叉树。
结果,代码如下啦:
#include<cstdio> #include<cmath> #include<cstring> const int maxn = 1e5 + 10; int bit[33 * maxn][2], n, k, a[maxn], t[35]; inline int max(int a, int b) {return a > b ? a : b;} void into(int x) { int p = 1,pos=0,i=0,tp=x; memset(t, 0, sizeof t); while (x) { t[p] = x % 2; x = x / 2; ++p; } for (i = 32; i; --i) { if(!bit[pos][t[i]]) bit[pos][t[i]] = ++k; pos = bit[pos][t[i]]; } } int find(int x) { int pos = 0, maxx = 0, ans[35] = { 0 }, p = 1, v = 0; memset(t, 0, sizeof t); while (x) { t[p] = x % 2; x = x / 2; ++p; } for (int i = 32; i; --i) { if (bit[pos][!t[i]])ans[i] = 1, v = !t[i]; else ans[i] = 0, v = t[i]; pos = bit[pos][v]; } for (int i = 32; i; --i) maxx += ans[i] * pow(2, i - 1); return maxx; } int main() { int ans = 0; freopen("C:\\Users\\Towetrlone\\Desktop\\qwq.txt", "r", stdin); scanf("%d", &n); for (int i = 1; i <= n; ++i) scanf("%d", &a[i]),into(a[i]); for (int i = 1; i <= n; ++i) ans = max(ans, find(a[i])); printf("%d", ans); return 0; }