小明的赈灾计划

思路:题意是求最大的区间异或和,首先利用异或的性质区间a[l~r]的异或和等于区间a[1~r]异或上a[1~l-1],因此把没个前缀异或和加入到trie树中

,然后考虑使得那个前缀和与某个前缀和的异或结果最大,即转化为trie树上求最大异或对的问题

 

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std ;

const int N = 4000010 ;

int tr[N][2],idx ;
int s[N] ;
int n ;

void add(int x){
    int p = 0 ;
    for(int i=30;i>=0;i--){
        int u = x >> i & 1 ;
        if(!tr[p][u]) tr[p][u] = ++ idx ;
        p = tr[p][u] ;
    }
}

int query(int x){
    int p = 0, res = 0 ;
    for(int i=30;i>=0;i--){
        int u = x >> i & 1 ;
        if(tr[p][!u]){
            res += 1 << i ;
            p = tr[p][!u] ;
        }else{
            p = tr[p][u] ;
        }
    }    
    return res ;
}

int main(){
    scanf("%d",&n) ;
    
    int ans = 0 ;
    add(0) ;//这里要插入0,考虑整个异或和的情况
    for(int i=1;i<=n;i++){
        int a ;
        scanf("%d",&a) ;
        s[i] = s[i-1] ^ a ;
        ans = max(ans,query(s[i])) ;
        add(s[i]) ;
    }
    
    printf("%d\n",ans) ;
    
    return 0 ;
}

 

#include <iostream>#include <cstring>#include <algorithm>
using namespace std ;
const int N = 4000010 ;
int tr[N][2],idx ;int s[N] ;int n ;
void add(int x){int p = 0 ;for(int i=30;i>=0;i--){int u = x >> i & 1 ;if(!tr[p][u]) tr[p][u] = ++ idx ;p = tr[p][u] ;}}
int query(int x){int p = 0, res = 0 ;for(int i=30;i>=0;i--){int u = x >> i & 1 ;if(tr[p][!u]){res += 1 << i ;p = tr[p][!u] ;}else{p = tr[p][u] ;}}return res ;}
int main(){scanf("%d",&n) ;int ans = 0 ;add(0) ;for(int i=1;i<=n;i++){int a ;scanf("%d",&a) ;s[i] = s[i-1] ^ a ;ans = max(ans,query(s[i])) ;add(s[i]) ;}printf("%d\n",ans) ;return 0 ;}

posted @ 2020-03-14 20:45  gulangyuzzz  阅读(174)  评论(0编辑  收藏  举报