#LOJ 10051 Nikitosh 和异或
#10051. 「一本通 2.3 例 3」Nikitosh 和异或
题意就是让着选两个区间,区间不能交叉,令他们的区间异或的和最大,怎么做?
这篇题解(Link)里有区间两个数异或最大值,想办法让这个区间异或值成两个点的区间异或,很显然,前缀异或。
异或也有前缀性。比如\(a \oplus b = c\),则 \(c \oplus b=a\),\(yh[l -r]=yh[l-1] \oplus yh[r]\)。
因为两区间不交叉,所以:
从前做一遍前缀异或,求出到 \(i\) 位置的最大异或值
从后做一遍后缀异或,求出到 \(i\) 位置的最大异或值
最后枚举分割点相加即可。
记得把零先插进去,因为说不定一段区间的前缀异或就是最大的而不是和到一个 \(l\) 的异或最大。
/*
Knowledge : Rubbish Algorithm
Work by :Gym_nastics
Time : O(AC)
*/
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int Mod=1e9+7;
const int N=2e6+6;
int read() {
int x=0,f=0;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) f|=(ch=='-');
for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch&15);
return f?-x:x;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(x>9) print(x/10);
putchar(x%10+48);
}
int Trie[N<<2][2],en[N<<2],tot;
void Insert(int x){
int pos=0;
for(int i=31;i>=0;i--){
int ch=((x>>i)&1);
if(!Trie[pos][ch]) Trie[pos][ch]=++tot;
pos=Trie[pos][ch];
}
en[pos]=true;
}
int search(int x){
int pos=0,res=0;
for(int i=31;i>=0;i--){
int ch=(((x>>i)&1)^1);
if(Trie[pos][ch]) res=res<<1|1,pos=Trie[pos][ch];
else res<<=1,pos=Trie[pos][ch^1];
} return res;
}
int a[N],Lmax[N],Rmax[N];
signed main() {
int n=read();int yh=0;Insert(0);
for(int i=1;i<=n;i++){
a[i]=read();yh^=a[i];Insert(yh);
Lmax[i]=max(Lmax[i-1],search(yh));
}memset(Trie,0,sizeof Trie);yh=0;
memset(en,0,sizeof en);tot=0;
for(int i=n;i>=1;i--){
yh^=a[i];Insert(yh);
Rmax[i]=max(Rmax[i+1],search(yh));
}int Ans=0;for(int i=1;i<n;i++)
Ans=max(Ans,Lmax[i]+Rmax[i+1]);
return print(Ans),0;
}