暴力解法(超时了)
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n;
int a[N];
int main()
{
cin >> n;
for (int i = 0; i < n; ++ i) cin >> a[i];
int res = 0;
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;
}
暴力解法的思路是,固定一个数a[i](第一重循环),然后在a[1]-a[n]中选出a[j](第二重循环),使得a[i] ^ a[j] 最大。对于每个a[i]都能求出一个最大值,对所有情况再取一个max就是要求的答案。
如何优化上面的程序呢?
对于第一步枚举a[i]不是很好优化,所以我们把优化的重点放在第二步(即当a[i]固定时,如何在a[1]-a[n]中选出a[j],使得a[i]与a[j]的异或值最大)
举个栗子
总结一下:首先对所有的a[i](i从1到n)根据每一位的0/1建立Trie数组,对每个固定的a[i],从根往下走,每次尽量往跟我当前这一位不同的分支上走,如果存在这样的分支就走过去,如果不存在,只好走跟我当前分支的这一位相同的分支了,这样的话走到底就一定能够得到最优解。
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010, M = 3000000;
int n;
int son[M][2], idx;
int a[N];
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 res = 0, p = 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()
{
cin >> n;
for (int i = 0; i < n; ++ i)
{
cin >> a[i];
insert(a[i]);
}
int res = 0;
for (int i = 0; i < n; ++ i) res = max(res, query(a[i]));
cout << res << endl;
return 0;
}
上述程序中,有个细节需要注意,int &s = son[p][x >> i & 1];
&的两种使用方法:一种是取地址符,一种是引用。
int a;
int *p = &a;
上面这种就是取地址符,指针p指向变量a,p中存放的是a的地址
int &c = b;
上面这是引用,定义一个引用就是说,c是b的一个别名,c就是代表b,改变c的值也就改变了b的值(注意:声明引用时必须要初始化,不能空声明,如:int &c是错的,int &c = b则可以)