题目
给定一个非负整数数列 a,初始长度为 N。
请在所有长度不超过 M 的连续子数组中,找出子数组异或和的最大值。
子数组的异或和即为子数组中所有元素按位异或得到的结果。
注意:子数组可以为空。
输入格式
第一行包含两个整数 N,M。
第二行包含 N 个整数,其中第 i 个为 ai。
输出格式
输出可以得到的子数组异或和的最大值。
数据范围
对于 20% 的数据,1≤M≤N≤100
对于 50% 的数据,1≤M≤N≤1000
对于 100% 的数据,1≤M≤N≤105,0≤ai≤231−1
输入样例:
3 2
1 2 4
输出样例:
6
一、主要思路
这题考察trie 数
,找出区间异或和最大值
区间的异或和 可以用前缀和 转化为两个点的异或和
此时题目就是求两个点的最大异或和,两个点之间有长度限制,长度限制可以用滑动窗口
解决
题目最难的地方在于在trie数中如何删除一个值
其实没有必要真的删除,只需要在创建trie树的时候加上一个cnt数组
,如果用到了该节点则加上val,在删除的时候cnt[p] 做减法即可
二、实现
代码如下:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N =( 1e5 + 10) * 31, M = 1e5 + 10;
int son[N][2],idx,arr[M], s[M],cnt[N];
void insert(int x, int val)
{
int p = 0;
for(int i = 30 ;i >= 0; i --)
{
int u = x >> i & 1;
if(!son[p][u])son[p][u] = ++idx;
p = son[p][u];
cnt[p] += val;
}
}
int query(int x)
{
int p = 0,res = 0;
for(int i = 30; i >= 0; i --)
{
int u = x >> i & 1;
if(cnt[ son[p][!u] ] )
{
res += 1 << i;
p = son[p][!u];
}
else p = son[p][u];
}
return res;
}
int main()
{
int n,m,res = 0;
cin>>n>>m;
for(int i = 1; i <= n; i ++ )
{
int x;
cin>>x;
s[i] = s[i - 1] ^ x;
}
insert(s[0],1);
for(int i = 1;i <= n; i ++ )
{
if(i > m )insert(s[i - m - 1], -1);
res = max(res, query(s[i]));
insert(s[i],1);
}
cout<<res;
}