传送门:Nikitosh 和异或
思路:异或相当于一个不进位的假发,所以普通加法有的一些性质,异或也有。
比如前缀异或和就相当于普通的前缀和。
假如现在要求一段区间[l,r]的异或值,只需要用sum[r]去异或sum[l-1]即可。
这道题的步骤大概就是
1.获取所有数据,求前缀异或和数组sum[i]并插入字典树当中,枚举每一个数据a[i],查询字典树中与它异或能获得的最大异或值,这一步就相当于是在找1~i中前缀异或值最大的区间,执行完n次查询后就可以获得最大的两个异或值相加就是答案。
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int N=4e5+10;
int son[N*30][2],idx;
int a[N];
int sum[N];
int l[N],r[N];
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];
}
}
int query(int x)
{
int res=0;
for(int p=0,i=30;i>=0;i--)
{
int u=x>>i&1;
if(son[p][!u])
{
res=res*2+1;
p=son[p][!u];
}else
{
res=res*2;
p=son[p][u];
}
}
return res;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]^a[i];
int lm=0,rm=0;
for(int i=1;i<=n;i++)
{
int t=query(sum[i]);
insert(sum[i]);
if(t>=lm)
{
lm=t;
rm=lm;
}else if(t<lm&&t>rm)
{
rm=t;
}
}
cout<<lm+rm;
return 0;
}