https://www.acwing.com/problem/content/1416/
给定一串序列,要找到异或值最大的子串。
在保证右端点最小的前提下保证长度最小。
对于异或的性质 a^b^a = b,可以将前缀和应用于该题。
这样的话只需要枚举左端点和右端点,但是时间复杂度为n^2,计算之后达到1e10。
所以就需要优化,我们可以用 Trie 树来优化上述思路。
枚举右端点,通过Trie树将查找操作的时间复杂度降为logn。
至于“在保证右端点最小的前提下保证长度最小”这个要求,保证右端点最小,从小开始枚举就好了,长度最小,如果两前缀异或相等,那么后者会将前者覆盖掉。
1 #include<iostream> 2 using namespace std; 3 const int N=1e5+10,M=N*21;//总共有N个数,每个数的范围为0~2^21-1 4 int s[N]; 5 int son[M][2],id[M],idx;//id用来存储以该节点做结尾的数的编号 6 void insert(int x,int k){ 7 int p=0; 8 for(int i=20;i>=0;i--){ 9 int u=x>>i&1; 10 if(!son[p][u]) son[p][u]=++idx; 11 p=son[p][u]; 12 } 13 id[p]=k; 14 } 15 int query(int x){ 16 int p=0; 17 for(int i=20;i>=0;i--){ 18 int u=x>>i&1; 19 if(son[p][!u]) p=son[p][!u]; 20 else p=son[p][u]; 21 } 22 return id[p]; 23 } 24 int main(void){ 25 int n; 26 cin>>n; 27 for(int i=1;i<=n;i++){ 28 cin>>s[i]; 29 s[i]^=s[i-1]; 30 } 31 int res=-1,a,b; 32 insert(s[0],0); 33 for(int i=1;i<=n;i++){ 34 int k=query(s[i]); 35 if((s[i]^s[k])>res)// > 的优先级高于^ 36 res=s[i]^s[k],a=k+1,b=i; 37 insert(s[i],i); 38 } 39 cout<<res<<" "<<a<<" "<<b; 40 return 0; 41 }