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;
}
posted @ 2018-11-02 18:35  水题收割者  阅读(154)  评论(0编辑  收藏  举报