题目链接
本题用到了以下知识点:
- 1.前缀和
- 2.trie
- 3.滑动窗口
首先: 这里需要求异或前缀和,其本质和普通的前缀和是一样的。
求 l 到 r 内的异或和等于 ans=s[r]^ s[l-1]。
2^2=0 即一个数异或其本身结果为0.
数组: 1,2,3
s[1]=1
s[2]=1^2
s[3]=1^2^3
区间[2,3]的异或和等于 s[3]^s[2-1]=s[3]^s[1]=1^2^3^1=1^2。
第二步: 建立一个二进制trie树。
第三步: 将不是滑动窗口的树删除(删除可以是设置一个数,表示删除),滑动窗口向后移动,插进新的数。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5*31+10,M=1e5+10;
int n,m;
int s[M];
int son[N][2],cnt[N],idx;
void insert(int x,int v)//插入
{
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]+=v;
}
}
int query(int x)//查询
{
int res=0,p=0;
for(int i=30;i>=0;i--)
{
int u=x>>i&1;
if(cnt[son[p][!u]]) p=son[p][!u],res=res*2+1;// !0=1, !1=0
else p=son[p][u],res=res*2;
}
return res;
}
int main(void)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int x; scanf("%d",&x);
s[i]=s[i-1]^x;
}
int res=0;
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);
}
printf("%d\n",res);
return 0;
}