[bzoj4260]Codechef REBXOR
Description
Input
输入数据的第一行包含一个整数\(N\),表示数组中的元素个数。
第二行包含N个整数\(A_1,A_2..A_N\)。
Output
输出一行包含给定表达式可能的最大值
Sample Input
5
1 2 3 1 2
Sample Output
6
HINT
满足条件的\((l1,r1,l2,r2)\)有:\((1,2,3,3),(1,2,4,5),(3,3,4,5)\)。
对于\(100%\)的数据,\(2 ≤ N ≤ 4*10^5,0 ≤ Ai ≤ 10^9\)。
Solution
这道题相当妙啊……
首先将数组分割成两部分。
设\(lmax[i]\)为原数组\([1,i]\)中的最大异或值,\(rmax[i]\)为原数组\([i,N]\)的最大异或值。
则我们只需要求出最大的\(lmax[i]+rmax[i+1]\)即可。
那么对于\(lmax[i]\)和\(rmax[i]\)的求法:
设\(Prefix[i]\)为原数组的前缀异或,对于任意的二元组\((i,j)\),\(x_i \oplus x_j = a_{i+1} \oplus a_{i+2} \oplus ... \oplus a_j\),\(a\)为原数组,\(i\leq j(i\geq 0)\)
那么就可以将问题转换为求二元组\((i,j)\),使得\(x_i \oplus x_j\)最大 ,\(x_i \oplus x_j\)即为\(lmax[i]\)。
对于\(rmax[i]\)也是同理。只需要反过来求即可。
那么如何求解最大的\(x_i \oplus x_j\)?
使用字典树,每次往里面先插入一个二进制数,然后再查找与其对应位相反的数即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 6
#define SIZE 3
int s[SIZE+1];
int a[MAXN];
int Prefix[MAXN];
int Sufix[MAXN];
int lmax[MAXN];
int rmax[MAXN];
int N;
int trie[MAXN<<5][2];
int tot = 1;
inline void make_string(int x){
for(register int i=SIZE;i>0;--i){
s[i] = x&1;
x>>=1;
}
}
inline int insert(){
int _next = 1;
for(register int i=1;i<=SIZE;++i){
int c = s[i];
if(trie[_next][c])_next = trie[_next][c];
else{
trie[_next][c] = ++tot;
_next = tot;
}
}
int sum = 0;
_next = 1;
for(register int i=1;i<=SIZE;++i){
int c = s[i]^1;
if(trie[_next][c]){
sum = (sum<<1) + 1;
_next = trie[_next][c];
}
else{
sum<<=1;
_next = trie[_next][c^1];
}
}
return sum;
}
int main(){
scanf("%d",&N);int NN = N;
for(register int i=1;i<=N;++i){
scanf("%d",&a[i]);
}
Prefix[0] = 0;
Sufix[N+1] = 0;
for(register int i=1;i<=N;++i){
Prefix[i] = a[i]^Prefix[i-1];
}
for(register int i=N;i>0;--i){
Sufix[i] = a[i]^Sufix[i+1];
}
tot = 1;
for(register int i=0;i<N;++i){
make_string(Prefix[i]);
lmax[i] = std::max(insert(),lmax[i-1]);
}
tot = 1;
std::memset(trie,0,sizeof(trie));
for(register int i=N+1;i>0;--i){
make_string(Sufix[i]);
rmax[i] = std::max(insert(),rmax[i+1]);
}
int maxx = 0;
for(register int i=1;i<NN;++i){
if(lmax[i]+rmax[i+1]>maxx)maxx = lmax[i]+rmax[i+1];
}
printf("%d",maxx);
return 0;
}