这里我只写了F题的题解,其他的都在视频题解里面
拿到这个题目,因为是一道区间询问的题目,就感觉像是数据结构,然而不知道什么数据结构能解决它。 下面我就带着大家来分析一下。
我们要求异或的最大值,那么我们就需要知道什么情况下a XOR b > a和b ,不要想复杂了,其实a和b二进制中最高位1的位置不同,那么就可以保证a XOR b > a和b了。 我们就从这个角度去思考这个问题。我们只需要知道序列中每一个数的最高位1出现在哪里就可以了,我们就可以直接判断它在不在区间[l,r]中,然后我们就可以不断得到最大值。 如何求序列中每一个元素得最高位1在序列中得位置呢,我们需要一个新的知识,就是线性基,如果大家知道线性基,那么这个问题就很简单了。如果不知道,那么这里有两篇博客大家可以看一下:线性基讲解1,线性基讲解2
现在我们已经知道了线性基了,我们就可以很容易得求出最高位1在序列中的位置了。 现在还有一个问题,这个题目是q次询问,我们就需要预处理,pos[i][j]表示到序列中第i个为止,最高位1出现在第j位的位置,举个例子:pos[5][7] = 5,那么a[5]就是序列中二进制最高位第7位是1的数。p[i][j]表示序列中到i为止,最高位j为1的数值,p[5][7] = 128,表示a[5] = 128。
那么我们在询问区间的时候,我们对于右端点r来说,只要pos[r][j]>=l,就表示满足条件的数在区间内,我们就异或起来。不断更新最大值。 复杂度线性O(n)。 下面是代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5+7;
int p[maxn][21],pos[maxn][21];
int a[maxn];
int n;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",a+i);
}
for(int i=1;i<=n;i++)
{
for(int j=20;j>=0;j--)
{
p[i][j] = p[i-1][j];
pos[i][j] = pos[i-1][j];
}
int tpos = i;
for(int j=20;j>=0;j--)
{
if((a[i]>>j)&1)
{
if(!p[i][j])
{
p[i][j] = a[i];
pos[i][j] = tpos;
break;
}
if(pos[i][j]<tpos)
{
swap(p[i][j],a[i]);
swap(pos[i][j],tpos);
}
a[i] ^= p[i][j];
}
}
}
int q;
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
int l,r;
scanf("%d%d",&l,&r);
int ans = 0;
for(int j=20;j>=0;j--)
{
if(pos[r][j]>=l) ans = max(ans,(ans^p[r][j]));
}
printf("%d\n",ans);
}
return 0;
}