小明的赈灾计划
思路:题意是求最大的区间异或和,首先利用异或的性质区间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 ;}