[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;
}
posted @ 2018-08-17 18:47  Neworld1111  阅读(89)  评论(0编辑  收藏  举报