bzoj 4260 Codechef REBXOR——trie树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4260
一段的异或和就是两个前缀的异或和。正反扫两边,用trie树算每个位置为左/右端点时最大异或和,并维护前/后缀max;然后枚举分界线即可。
注意&出来是值,要弄一弄才能变成bool。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=4e5+5,M=30; int n,a[N],bin[M+5],tot,c[N*M][2],s[N][2],mx,ans; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return fx?ret:-ret; } void init() { bin[0]=1;for(int i=1;i<=n;i++)bin[i]=bin[i-1]<<1; } int calc(int sm) { int cr=0,ret=0; for(int i=mx,d;i>=0;i--) { d=((sm&bin[i])>0);//((__)>0) if(c[cr][!d])cr=c[cr][!d],ret|=bin[i]; else cr=c[cr][d]; } return ret; } void insert(int sm) { int cr=0; for(int i=mx,d;i>=0;i--) { d=((sm&bin[i])>0);// if(!c[cr][d])c[cr][d]=++tot; cr=c[cr][d]; } } int main() { n=rdn(); init(); for(int i=1;i<=n;i++)a[i]=rdn(),mx=max(mx,a[i]); for(int i=30;i>=0;i--)if(mx&bin[i]){mx=i;break;} int sm=0; insert(0);//after cal mx! for(int i=1;i<=n;i++) { sm^=a[i]; s[i][0]=max(s[i-1][0],calc(sm)); insert(sm); } tot=0;memset(c,0,sizeof c);insert(0); sm=0; for(int i=n;i;i--) { sm^=a[i]; s[i][1]=max(s[i+1][1],calc(sm)); insert(sm); } for(int i=1;i<n;i++) ans=max(ans,s[i][0]+s[i+1][1]); printf("%d\n",ans); }