qiancl:你认识jpy吗,比你高明到不知道哪里去了
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4260
大意:给你一列数,找出两段连续的区间[l,r],[L,R],使得f([l,r])+f([L,R])最大,f()表示这段区间每个数按位异或。
当我看到这道题的时候,我还不知道前缀异或和的性质,然后我假设成立,写了两段代码拍了拍,发现是对的。
于是就有了一个很显然的做法,你把前缀异或和求出来一个一个数转成二进制放到一颗trie里去,对于当前1..i这些数的异或和在trie上找一串异或起来最大的串,就能知道以当前第i个点为右端点,向左能得到的最大区间异或值,同理,再求一遍后缀异或和。
然后你就得到了两个数组l,r,l[i]表示向左能取到的最大值,r[j]表示向右能取到的最大值,问题转化成求在i<j时,l[i]+r[j]的最大值,这个O(n)扫一遍就行了。
总算法复杂度O(n lgn)
代码奇丑无比(不知道怎么清空指针trie
/************************************************************** Problem: 4260 User: qiancl Language: C++ Result: Accepted Time:5020 ms Memory:196220 kb ****************************************************************/ #include<cstring> #include<cstdio> #include<algorithm> using namespace std; #define N 400010 struct node{node *ch[2];}root,root1,tree[30*N],tree1[30*N]; int n,m,p,k,mx,ans,p3,o[N],l[N],r[N],L[N],R[N];bool f[31]; inline void add(bool a[]){ node *loc=&root;int k=1; while(k<=30){ if(loc->ch[a[k]]==NULL)loc->ch[a[k]]=&tree[p++]; loc=loc->ch[a[k]],++k; } } inline void add1(bool a[]){ node *loc=&root1;int k=1; while(k<=30){ if(loc->ch[a[k]]==NULL)loc->ch[a[k]]=&tree1[p3++]; loc=loc->ch[a[k]],++k; } } #define nc() getchar() inline int read(){ int x=0;char ch=nc();for(;ch<'0'||ch>'9';ch=nc()); for(;ch<='9'&&ch>='0';x=x*10+ch-48,ch=nc());return x; } inline int find(bool a[]){ node *loc=&root;int k=1,o=1<<29,ans=0; while(k<=30){ if(loc->ch[a[k]^1]==NULL)ans+=o*(a[k]),loc=loc->ch[a[k]]; else ans+=o*(a[k]^1),loc=loc->ch[a[k]^1];++k,o>>=1; }return ans; } inline int find1(bool a[]){ node *loc=&root1;int k=1,o=1<<29,ans=0; while(k<=30){ if(loc->ch[a[k]^1]==NULL)ans+=o*(a[k]),loc=loc->ch[a[k]]; else ans+=o*(a[k]^1),loc=loc->ch[a[k]^1];++k,o>>=1; }return ans; } int main(){ n=read(),add(f),add1(f); for(int i=1;i<=n;o[i]=read(),++i); for(int i=1,x=0,k;i<=n;++i){ x=(L[i]=o[i]^L[i-1]),k=30,memset(f,0,sizeof f); while(x)f[k--]=x%2,x>>=1; add(f),l[i]=L[i]^find(f); } for(int i=n,x=0,k;i>=1;--i){ x=(R[i]=o[i]^R[i+1]),k=30,memset(f,0,sizeof f); while(x)f[k--]=x%2,x>>=1; add1(f),r[i]=R[i]^find1(f); }ans=0;int mx=0; for(int i=1;i<n;++i){ if(l[i]>mx)mx=l[i]; if(mx+r[i+1]>ans)ans=mx+r[i+1]; } printf("%d",ans); }
loading...