题意:
给你一个长度为n的序列,让你选择你个连续的子序列做Xor操作求最大值为多少?并且该区间是什么?(如果有多个解,则取右边界最小(第一关键词),区间长度最短(第二关键词))。
思路:
对数组求前缀异或和,即求[1,2][1,3]....[1,n]等区间的异或和,然后你将二个区间异或后可以发现是一个连续区间的异或和。然后用01trie求取结果。
注意当n=1时的结果。
代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; int a[33], cnt[3200005][2], ji=1; ll pa[100005]; ll ma=-1; void Insert() { int now=0, i=31; while(i>=0) { if(cnt[now][a[i]]==-1) { cnt[now][a[i]]=ji; ji++; } now=cnt[now][a[i]]; i--; } } ll fun() { ll now=0, p=0, k=(1LL<<31), i=31; while(i>=0) { if(a[i]==1&&cnt[now][0]!=-1) { p=p+k; now=cnt[now][0]; } else if(a[i]==0&&cnt[now][1]!=-1) { p=p+k; now=cnt[now][1]; } else if(a[i]==1&&cnt[now][1]!=-1) { now=cnt[now][1]; } else { now=cnt[now][0]; } i--; k=k/2; } return p; } int main() { int n, r=-1; scanf("%d",&n); memset(cnt,-1,sizeof(cnt)); for(int i=0; i<n; i++) { scanf("%lld",&pa[i]); } ma=pa[0]; for(int i=0; i<n; i++) { if(i!=0) { pa[i]=pa[i-1]^pa[i]; } int x=pa[i]; for(int j=0; j<32; j++) { a[j]=x%2; x=x/2; } Insert(); ll pan=fun(); if(pan>ma) { ma=pan; r=i; } } //printf("%lld %lld\n",pa[1],pa[2]); ll l=-1; for(int i=r-1; i>=0; i--) { if((pa[i]^pa[r])==ma) { l=i; //printf("%lld %lld\n",pa[i],pa[r]); //printf("l=%lld\n",r); break; } } if(pa[0]==ma) { cout << pa[0] << " " << 1 << " " << 1 << endl; } else { cout << ma << " " << l+2 << " " << r+1 << endl; } return 0; }