[bzoj4260]Codechef REBXOR

传送门

Description

fa(1).jpg

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;
}

转载于:https://www.cnblogs.com/Neworld2002/p/9494884.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值