地址:https://www.acwing.com/problem/content/145/
没买课的话,应该打不开题。我就截个图吧,题意是很简单的。
解析:
1:贪心思路
首先明确,什么是异或运算,两个数不同,则为1,否则为0。
给定ai,如果想让ai和一个数的异或结果最大,很明显,要从高位开始看,尽量从高位筛选同位不同数的数字。
举个例子:
10:1010
x
从高位(第3位)开始看,10的第三位为1,最优解是x的第三位与它不同,为0。10的第二位为0,最优解是x的第二位为1......以此类推。
这就是贪心的思路。
2:字典序优化
怎么优化呢?暴力跑的话是n*n。
发现每个数字化为二进制的话,按题中范围最大为31位。直接跑字典序的话,复杂度可以优化到n*31
如图所示:
总结一下,对于当前的二进制位,如果存在与它不同的,就走过去,否则,只能沿着仅存的那条路走了。
由于N是1e5,假设每个数都有31位而且都占有新节点,那么最多一共需要N*31个节点位,即要开到son[N*31][31]
代码:
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
const int maxn=1e5+10,maxn2=31*maxn;
int idx=0;
typedef long long ll;
int a[maxn];
int son[maxn2][2];
void insert(int x)
{
int p=0;
for(int i=30;i>=0;i--)
{
int u = x>>i&1;
if(!son[p][u])
son[p][u]=++idx;
p=son[p][u];
}
return ;
}
int query(int x)
{
int res=0;
int p=0;
for(int i=30;i>=0;i--)
{
int u=x>>i&1;
if(son[p][!u])
{
res=res*2+1;
p=son[p][!u];
}
else
{
p=son[p][u];
res=res*2;
}
}
return res;
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
insert(a[i]);
}
int maxx=0;
for(int i=1;i<=n;i++)
{
maxx=max(maxx,query(a[i]));
}
cout<<maxx<<endl;
return 0 ;
}