bzoj4260 Codechef REBXOR
分析
01trie树好题!
我们先考虑将序列变为前缀和形式,在从1到n遍历每一个i
对于每一个i,我们把pre[i]插入trie中,在求出pre[i]与之前数的最大异或值
于是我们就可以得到dp[i]表示前i个数中是最大异或值
转移为dp[i]=Max{dp[i-1],q(pre[i])}
这样我们就可以找到l1,r1的最优策略
然后我们再用相似思路跑一遍后缀求出dp2表示l2,r2
于是Ans = Max{dp[i]+dp2[i+1]}
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
int son[31*400005][2],cnt;
int a[400100],now,dp[400100];
int a2[400100],b2[400100],dp2[400100];
inline int q(int x){
int res=0,i,p=0;
for(i=30;i>=0;i--){
int wh=(x&(1<<i))?0:1;
if(son[p][wh]){
p=son[p][wh];
res|=(1<<i);
}else p=son[p][!wh];
}
return res;
}
inline void ins(int x){
int i,p=0;
for(i=30;i>=0;i--){
int wh=(x&(1<<i))?1:0;
if(!son[p][wh])
son[p][wh]=++cnt;
p=son[p][wh];
}
return;
}
int main(){
int n,m,i,j,k;
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
now=0;
ins(0);
for(i=1;i<=n;i++){
now^=a[i];
ins(now);
dp[i]=max(dp[i-1],q(now));
}
memset(son,0,sizeof(son));
now=cnt=0;
ins(0);
for(i=n;i>0;i--){
now^=a[i];
ins(now);
dp2[i]=max(dp2[i+1],q(now));
}
int Ans=0;
for(i=1;i<n;i++)Ans=max(Ans,dp[i]+dp2[i+1]);
cout<<Ans;
return 0;
}