【题解 P8773】 选数异或
[蓝桥杯 2022 省 A] 选数异或
题目描述
给定一个长度为 \(n\) 的数列 \(A_{1}, A_{2}, \cdots, A_{n}\) 和一个非负整数 \(x\), 给定 \(m\) 次查询, 每次询问能否从某个区间 \([l, r]\) 中选择两个数使得他们的异或等于 \(x\) 。
输入格式
输入的第一行包含三个整数 \(n, m, x\) 。
第二行包含 \(n\) 个整数 \(A_{1}, A_{2}, \cdots, A_{n}\)。
接下来 \(m\) 行,每行包含两个整数 \(l_{i}, r_{i}\) 表示询问区间 \(\left[l_{i}, r_{i}\right]\) 。
输出格式
对于每个询问, 如果该区间内存在两个数的异或为 \(x\) 则输出 yes
, 否则输出 no
。
样例 #1
样例输入 #1
4 4 1
1 2 3 4
1 4
1 2
2 3
3 3
样例输出 #1
yes
no
yes
no
提示
【样例说明】
显然整个数列中只有 2,3 的异或为 1 。
【评测用例规模与约定】
对于 \(20 \%\) 的评测用例, \(1 \leq n, m \leq 100\);
对于 \(40 \%\) 的评测用例, \(1 \leq n, m \leq 1000\);
对于所有评测用例, \(1 \leq n, m \leq 10^5,0 \leq x<2^{20}, 1 \leq l_{i} \leq r_{i} \leq n\) , \(0 \leq A_{i}<2^{20}\) 。
蓝桥杯 2022 省赛 A 组 D 题。
解题思路
对于区间内两个数 \(a_l,a_r\) ,若他们 \(a_l \oplus a_r = x\) ,则有 \(a_r \oplus x=a_l\) 。
预处理出每个 \(a_r\) 前与他距离最近的且满足要求的 \(a_l\) 的下标,设为 \(pre_r\)。
那么,若一段区间 \([l,r]\) 内存在两个数异或和为 \(x\) ,必存在一个 \(a_r\) ,其 \(pre_r \ge l\) 。
那就是求 \(max_{i=l}^{r} pre_i\) 是否 $ \ge l$ 就好了。
可以用线段树或 \(ST\) 表,时间复杂度 \(O(nlogn)\) 。
#include<bits/stdc++.h>
using namespace std;
long long n,m,k,a[100005],last[100005],b[1000005],f[100005][21],p[21],l[100005];
long long dijah(long long x,long long y)
{
long long z=l[y-x+1];
return max(f[x][z],f[y-p[z]+1][z]);
}
int main()
{
long long x,y;
scanf("%lld%lld%lld",&n,&m,&k);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
for(int i=1;i<=n;i++)
{
f[i][0]=last[i]=b[a[i]^k];
b[a[i]]=i;
}
l[0]=-1;
p[0]=1;
for(int i=1;i<=n;i++)l[i]=l[i/2]+1;
for(int i=1;i<=20;i++)p[i]=p[i-1]*2;
for(int i=1;i<=20;i++)
{
for(int j=1;j+p[i]-1<=n;j++)
{
f[j][i]=max(f[j][i-1],f[j+p[i-1]][i-1]);
}
}
for(int i=1;i<=m;i++)
{
scanf("%lld%lld",&x,&y);
if(dijah(x,y)>=x)printf("yes\n");
else printf("no\n");
}
return 0;
}