【题解 P8773】 选数异或

发布时间 2023-10-18 11:36:50作者: dijah

[蓝桥杯 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;
}