题意:
区间长度为n的数组a,取连续一段子序列,问哪段子序列的异或和最大,如果存在多个这样的序列,那么选择序列末端整数对应的编号更小的那个序列。
如果仍然存在多个可选的序列,那么选择长度最短的那个序列。
题解:
01字典树模板题
简单说一下,我们每次是将异或值的前缀和sum存在树中
对于每次插入第j个sum,如果找到之前的第i个sum和其异或值最大,那么求的的区间就是[i,j],
代码:
#include<bits/stdc++.h> using namespace std; const int maxn =1e7+10; const int MaxN = 0x3f3f3f3f; const int MinN = 0xc0c0c00c; typedef long long ll; const int inf=0x3f3f3f3f; const ll mod=1e9+7; using namespace std; int n,total; int trie[maxn][2],num[maxn]; void ins(int val,int x){ int node=0; for(int i=21;i>=0;i--){ int t=(val>>i)&1; if(!trie[node][t]){ trie[node][t]=++total; } node=trie[node][t]; } num[node]=x; } pair<int,int> quer(int val){ int node=0,res=0; for(int i=21;i>=0;i--){ int t=(val>>i)&1; if(trie[node][t^1]){//因为异或是不同为1,所以优先找不同于当前位t的 res|=1<<i; node=trie[node][t^1]; } else node=trie[node][t]; } return make_pair(res,num[node]); } int main() { ios::sync_with_stdio(false); int n; cin>>n; int ans=-1,l,r,sum=0; ins(sum,0); for(int i=1;i<=n;i++){ int x; cin>>x; sum^=x; auto res=quer(sum); ins(sum,i); if(res.first>ans) { ans=res.first; l=res.second; r=i; } } cout<<ans<<" "<<l+1<<" "<<r<<endl; return 0; }