最大异或对

在给定的N个整数A1A2ANA1,A2……AN中选出两个进行xor(异或)运算,得到的结果最大是多少?

输入格式

第一行输入一个整数N。

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

输出格式

输出一个整数表示答案。

数据范围

1N1051≤N≤105,
0Ai<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

posted @ 2020-06-04 09:31  Vincent&  阅读(237)  评论(0编辑  收藏  举报