输入数据的第一行包含一个整数N,表示数组中的元素个数。
第二行包含N个整数A1,A2,…,AN。
输出一行包含给定表达式可能的最大值。
满足条件的(l1,r1,l2,r2)有:(1,2,3,3),(1,2,4,5),(3,3,4,5)。
对于100%的数据,2 ≤ N ≤ 4*105,0 ≤ Ai ≤ 109。
题意: 很清楚。
思路: 维护一个前缀, qian[i] 表示到第i 位的区间异或的最大值。 同理,维护一个后缀。 那么答案就是后缀+前缀。 维护的时候用01字典树来维护。
另外,这个题真的好卡时间呀。。。 从32 开始就不可以竟然。 可怕。
代码:
#include<bits/stdc++.h>
using namespace std;
#define Memset(x, a) memset(x, a, sizeof(x))
typedef long long ll;
const int maxn = 400000 + 5;//集合中的数字个数
int ch[32*maxn][2]; //节点的边信息
ll val[32*maxn]; //节点存储的值
int sz; //树中当前节点个数
int num[32*maxn]; // 出现的次数
void init(){
Memset(ch[0],0); //树清空
memset(num,0,sizeof(num));
sz=1;
}
void _insert(ll a){//在字典树中插入 a
//和一般字典树的操作相同 将X的二进制插入到字典树中
int rt=0;
for(int i=31;i>=0;i--){
int c=((a>>i)&1);
if(!ch[rt][c]){
Memset(ch[sz],0);
val[sz]=0;
num[sz]=0;
ch[rt][c]=sz++;
}
rt=ch[rt][c];
num[rt]++;
}
val[rt]=a; //最后的节点插入value
}
ll query(ll a){ //在字典树中查找和a异或的值最大的元素b 返回b的值
int rt=0;
for(int i=31;i>=0;i--){
int c=((a>>i)&1);
if(ch[rt][c^1]&&num[ch[rt][c^1]]) rt=ch[rt][c^1];//c=0,b=c^1=1,b^c=1;c=1,b=c^1=0,b^c=1;
else rt=ch[rt][c];
}
return a^val[rt];
}
void update(ll a,int d)
{
int rt=0;
for(int i=31;i>=0;i--)
{
int c=((a>>i)&1);
rt=ch[rt][c];
num[rt]+=d;
}
return ;
}
const int N=4e5+5;
ll a[N];
ll qian[N];
ll hou[N];
int n;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
init();
ll x=0;
_insert(0);
for(int i=1;i<=n;i++){
x=x^a[i];
//printf("%lld\n",x);
_insert(x);
qian[i]=query(x);
//printf("qian : %lld\n",qian[i]);
qian[i]=max(qian[i],qian[i-1]);
}
init();
ll ans=-1;
x=0;
_insert(0);
for(int i=n;i>=1;i--){
x=x^a[i];
_insert(x);
hou[i]=query(x);
hou[i]=max(hou[i],hou[i+1]);
ans=max(ans,qian[i-1]+hou[i]);
}
printf("%lld\n",ans);
return 0;
}