BZOJ 4260 Codechef REBXOR 01trie

好题。。。开阔思路


 

把每个前缀异或和依次插入$01trie$,插之前找一个最优的(就是从高位向低位贪心,尽量走相反方向)看看能不能更新答案,此时相当于找到了区间右端点不超过某个点$r$的最大或和$f[r]$。对于后缀也同理来一波上面的操作,然后就找到了区间左端点端点不少于某个点$l$的最大异或和。所以答案就是$max(f[某个位置]+query(下个位置开始的后缀))$。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define R register int
using namespace std;
namespace Fread {
    static char B[1<<15],*S=B,*D=B;
    #define getchar() (S==D&&(D=(S=B)+fread(B,1,1<<15,stdin),S==D)?EOF:*S++)
    inline int g() {
        R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
        do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
    } inline bool isempty(const char& ch) {return ch<=36||ch>=127;}
    inline void gs(char* s) {register char ch; while(isempty(ch=getchar())); do *s++=ch; while(!isempty(ch=getchar()));}
}using Fread::g; using Fread::gs;
const int N=400010;
int t[N*32][2],tot,n,a[N],s[N],b[N],f[N],ans;
inline void ins(int x) { R now=0;
    for(R i=31;~i;--i) {
        R ch=(x>>i)&1;
        if(!t[now][ch]) t[now][ch]=++tot;
        now=t[now][ch];
    }
}
inline int query(int x) { R now=0,ret=0;
    for(R i=31;~i;--i) {
        R ch=(x>>i)&1;
        if(!t[now][ch^1]) now=t[now][ch^1];
        else now=t[now][ch^1],ret+=(1<<i);
    } return ret;
}
signed main() {
#ifdef JACK
    freopen("NOIPAK++.in","r",stdin);
#endif
    n=g(); for(R i=1;i<=n;++i) a[i]=g();
    for(R i=1;i<=n;++i) s[i]=s[i-1]^a[i];
    for(R i=n;i;--i) b[i]=b[i+1]^a[i]; ins(0);
    for(R i=1;i<=n;++i) f[i]=max(f[i-1],query(s[i])),ins(s[i]);
    memset(t,0,sizeof(t)); tot=0; ins(0); 
    for(R i=n;i;--i) ans=max(ans,f[i-1]+query(b[i])),ins(b[i]);
    printf("%d\n",ans);
}

2019.06.13

 

posted @ 2019-06-13 00:11  LuitaryiJack  阅读(175)  评论(0编辑  收藏  举报