BZOJ 4260: Codechef REBXOR(01trie+思维)
求两个不相交区间异或和的和最大.
设l[i]是1~i一段区间的最大异或和,r[i]是i~n一段区间的最大异或和,题意就是求max(l[i]+r[i+1]);
那么只要求l,r数组。
设num数组是个前缀异或和,根据异或的性质,我们要求i~j的异或和就是num[i]^num[j],所以对于l数组,我们要求出max(num[i]^num[j]),r数组用后缀异或和同理.
l[i]=max(l[i-1],find(num[i-1]^a[i])) l[i-1]表示区间不包括i,否则就是用find函数找区间包括i的值.find函数就是再trie树上尽量往相反的方向爬。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 #include <queue> 7 #include <map> 8 #define ll long long 9 #define out(a) printf("%d",a) 10 #define writeln printf("\n") 11 const int N=4e5+50; 12 const int MOD=1e9+7; 13 using namespace std; 14 int n; 15 int tot=1; 16 int a[N]; 17 int num[N],l[N],r[N]; 18 int trie[N*31][2]; 19 int ans; 20 int read() 21 { 22 int s=0,t=1; char c; 23 while (c<'0'||c>'9'){if (c=='-') t=-1; c=getchar();} 24 while (c>='0'&&c<='9'){s=s*10+c-'0'; c=getchar();} 25 return s*t; 26 } 27 ll readl() 28 { 29 ll s=0,t=1; char c; 30 while (c<'0'||c>'9'){if (c=='-') t=-1; c=getchar();} 31 while (c>='0'&&c<='9'){s=s*10+c-'0'; c=getchar();} 32 return s*t; 33 } 34 void insert(int x) 35 { 36 int u=1; 37 for (int i=31;i>=0;i--){ 38 int c=((1<<i)&x)>0; 39 if (!trie[u][c]) trie[u][c]=++tot; 40 u=trie[u][c]; 41 } 42 } 43 int find(int x) 44 { 45 int u=1,res=0; 46 for (int i=31;i>=0;i--){ 47 int c=((1<<i)&x)>0; 48 if (trie[u][1-c]) u=trie[u][1-c],res+=(1<<i); 49 else u=trie[u][c]; 50 } 51 return res; 52 } 53 int main() 54 { 55 n=read(); 56 for (int i=1;i<=n;i++){ 57 a[i]=read(); 58 insert(num[i-1]); 59 num[i]=num[i-1]^a[i]; 60 l[i]=max(l[i-1],find(num[i])); 61 } 62 memset(trie,0,sizeof(trie)); 63 for (int i=n;i;i--){ 64 insert(num[i+1]); 65 num[i]=num[i+1]^a[i]; 66 r[i]=max(r[i+1],find(num[i])); 67 ans=max(ans,l[i]+r[i+1]); 68 } 69 out(ans); 70 return 0; 71 } 72 73