[BZOJ4260] Codechef REBXOR

传送门 - > \(bzoj4260\)

题目描述

给定一个含N个元素的数组A,下标从1开始,请找出下面式子的最大值:
(A[11]^ A[11+1] ^ … ^ A[r1]) + (A[12] ^ A[12+1]^ … ^A[r2])。
其中,\(1<11<rl<l2<r2<N\)。式中x^y表示x和y的按位异或运算。

输入

输入数据的第一行包含一个整数N,表示数组中的元素个数。
第二行包含N个整数A1,A2,…,AN。

输出

输出一行包含给定表达式可能的最大值。

样例输入

5
1 2 3 1 2

样例输出

6

提示

对于100%的数据,\(2 ≤ N ≤ 4*10^5\)\(0 ≤ Ai ≤ 10^9\).

题解

题目要求求出两段区间异或和之和最大,且这两个区间是递增的,没有交集,那么可以求出前缀最大异或和lmax以及后缀最大异或和rmax,其中lmax[i]代表[1,i]中一段区间的最大异或值,rmax[i]代表[i,n]中一段区间的最大异或值
求出这两个值后,\(ans=max(ans,lmax[i]+rmax[i+1]),1<=i<=n\).
那么怎么求出lmax和rmax呢,很显然在求这两个数组时是可以使用trie树前缀异或和优化的,即trie树保存的是前缀异或和d[i],表示\(1-i\)的异或和.
我们知道trie树可以线性求出两个值的最大异或和,那么d[i]^trie树中的一个值x,其中\(x\in({d[j]|1<=j<i})\),这样就可以求出[j,i]这段区间的异或和
假如当前我们需要求出lmax[i],且d[1]~d[i-1]均已插入trie树中,
那么lmax[i]=max(lmax[i-1],find(d[i-1]^a[i])).其中find()函数是trie的检索函数,是用来求出最大异或和的
至于rmax,倒着做一遍就好了
trie树数组最大要开12000000*2,不会爆内存的

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<string>
#include<ctime>
#define Min(a,b) (a)<(b)?(a):(b)
#define Max(a,b) (a)>(b)?(a):(b)
#define in(i) (i=read())
using namespace std;
const double delta=0.998;
typedef long long lol;
int read() {
    int ans=0,f=1; char i=getchar();
    while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
    while(i>='0' && i<='9') {ans=(ans<<1)+(ans<<3)+i-'0'; i=getchar();}
    return ans*f;
}
int n,ans,tot;
int a[400010],d[400010],trie[12000010][2];
int lmax[400010],rmax[400010];
void insert(int x) {
    int p=0;
    for(int i=30;i>=0;i--) {
        int c=x>>i&1;
        if(!trie[p][c]) trie[p][c]=++tot;
        p=trie[p][c];
    }
}
int find(int x) {
    int ans=0,p=0;
    for(int i=30;i>=0;i--) {
        int c=x>>i&1,o=c^1;
        if(trie[p][o]) ans=ans<<1|1,p=trie[p][o];
        else ans<<=1,p=trie[p][c];
    }
    return ans;
}
int main()
{
    in(n);
    for(int i=1;i<=n;i++) {
        in(a[i]);
        insert(d[i-1]);
        lmax[i]=Max(lmax[i-1],find(d[i]=d[i-1]^a[i]));
    }
    memset(trie,0,sizeof(trie)),tot=0;
    for(int i=n;i>=1;i--) {
        insert(d[i+1]);
        rmax[i]=Max(rmax[i+1],find(d[i]=d[i+1]^a[i]));
    }
    for(int i=1;i<=n;i++) 
        ans=Max(ans,lmax[i]+rmax[i+1]);
    cout<<ans<<endl;
}

博主蒟蒻,随意转载.但必须附上原文链接

http://www.cnblogs.com/real-l/

posted @ 2018-08-14 12:10  real_l  阅读(417)  评论(0编辑  收藏  举报