1. 程式人生 > >2018.09.26【BZOJ4260】Codechef REBXOR(01Trie)

2018.09.26【BZOJ4260】Codechef REBXOR(01Trie)

傳送門

解析:

這種要求分成兩段的問題,一般就是處理出一個字首最大和一個字尾最大。 然後O(n)O(n)掃一遍就好了。

那麼,怎麼求?

這種異或問題當然還是要01Trie01Trie了。

思路:

我們可以順序做一遍,再倒序相同的求一遍。

我們先在Trie樹中插入一個0,因為之後的詢問可能包含全部的字首異或。

我們利用sumsum記錄一下字首xorxor,然後每次插入後在TrieTrie中貪心找以當前位置開頭的最大xorxor和。

之後更新一下prepresufsuf陣列。仍然使用遞推。

最後就是直接查詢就好了啊。

程式碼:

#include
<bits/stdc++.h>
using namespace std; #define ll long long #define re register #define gc getchar #define pc putchar #define cs const inline ll getint(){ re ll num; re char c; while(!isdigit(c=gc()));num=c^48; while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48); return num; } inline
void outint(ll a){ static char ch[23]; if(!a)pc('0'); while(a)ch[++ch[0]]=a-a/10*10,a/=10; while(ch[0])pc(ch[ch[0]--]^48); } cs int N=400005; struct _01TRIE{ int son[N*32][2]; int tot; _01TRIE(){tot=0;memset(son,0,sizeof son);} void clear(){tot=0;memset(son,0,sizeof son);} void insert(int x){ int now=0; for
(int re i=30;~i;--i){ bool f=(x>>i)&1; if(!son[now][f])son[now][f]=++tot; now=son[now][f]; } } int query(int x){ int ans=0; int now=0; for(int re i=30;~i;--i){ bool f=(x>>i)&1; if(son[now][!f]){ ans|=1<<i; now=son[now][!f]; } else now=son[now][f]; } return ans; } }Trie; int n,sum; int a[N],pre[N],suf[N]; signed main(){ n=getint(); for(int re i=1;i<=n;++i)a[i]=getint(); Trie.insert(0); for(int re i=1;i<=n;++i){ sum^=a[i]; Trie.insert(sum); pre[i]=max(pre[i-1],Trie.query(sum)); } Trie.clear(); Trie.insert(0); sum=0; for(int re i=n;i>=1;--i){ sum^=a[i]; Trie.insert(sum); suf[i]=max(suf[i+1],Trie.query(sum)); } int ans=0; for(int re i=0;i<=n;++i){ ans=max(ans,pre[i]+suf[i+1]); } outint(ans); return 0; }