题目描述
输入格式
输出格式
样例
数据范围与提示
题解
首先记录异或前缀和$s[i]=a[1]⊕a[2]⊕a[3] ...⊕a[i]$。
设$l[i]$为以$i$结尾的区间中,异或值的最大值。
因为异或有 $x⊕x=0$ 的性质,所以区间 $[l,r]$ 的异或值
$=a[l]⊕a[l+1]⊕...⊕a[r]$
$=(a[1]⊕a[2]⊕a[3]...⊕a[l-1])⊕(a[1]⊕a[2]⊕a[3] ...⊕a[r])$
$=s[l-1]⊕s[r]$,
所以求$l[i]$,转化为找$j<i$,使得$s[j]⊕s[i]$最大。
转化为「LOJ#10050」「一本通 2.3 例 2」The XOR Largest Pair(Trie
以相似的方法可以求出$r[i]$(以$i$开头的区间中,异或值的最大值)。
在实际操作的过程中可以$l[i]=max(l[i-1],find(x))$,这样$ans=max(l[i]+r[i+1])$就行了。
书上的操作是直接$l[i]=find(x)$然后$ans=max(l[i]+r[i+1])$,感觉不能理解qwq
1 编号 题目 状态 分数 总时间 内存 代码 / 答案文件 提交者 提交时间 2 #237651 #10051. 「一本通 2.3 例 3」Nikitosh 和异或 Accepted 100 2765 ms 43900 KiB C++ / 1.2 K qwerta 2018-10-20 17:15:56 3 4 #include<iostream> 5 #include<cstring> 6 #include<cstdio> 7 #include<cmath> 8 using namespace std; 9 int s[400003]; 10 int l[400003]; 11 int r[400003]; 12 struct emm{ 13 int nxt[2]; 14 }a[12800003]; 15 int cnt=0; 16 int b[33]; 17 void add(int x) 18 { 19 int j=-1; 20 memset(b,0,sizeof(b)); 21 while(x) 22 { 23 b[++j]=x&1; 24 x>>=1; 25 } 26 int k=0; 27 for(int j=32;j>=0;--j) 28 { 29 if(!a[k].nxt[b[j]]) 30 a[k].nxt[b[j]]=++cnt; 31 k=a[k].nxt[b[j]]; 32 } 33 return; 34 } 35 int find(int x) 36 { 37 int now=0,k=0; 38 for(int j=32;j>=0;--j) 39 { 40 if(a[k].nxt[1-b[j]]) 41 { 42 now+=(1<<j); 43 k=a[k].nxt[1-b[j]]; 44 } 45 else k=a[k].nxt[b[j]]; 46 } 47 return now; 48 } 49 int main() 50 { 51 //freopen("a.in","r",stdin); 52 int n; 53 scanf("%d",&n); 54 for(int i=1;i<=n;++i) 55 scanf("%d",&s[i]); 56 int x=0; 57 for(int i=1;i<=n;++i) 58 { 59 x^=s[i];//这里的x为前缀和 60 add(x); 61 l[i]=max(l[i-1],find(x)); 62 } 63 //重做一次找r[i] 64 memset(a,0,cnt+1); 65 x=0,cnt=0; 66 for(int i=n;i;--i) 67 { 68 x^=s[i]; 69 add(x); 70 r[i]=max(r[i+1],find(x)); 71 } 72 int ans=0; 73 for(int i=1;i<n;++i) 74 ans=max(ans,l[i]+r[i+1]); 75 cout<<ans; 76 return 0; 77 }