题目
给定一个长度为 n 的数列 A1,A2,⋅⋅⋅,An 和一个非负整数 x,给定 m 次查询,每次询问能否从某个区间 [l,r] 中选择两个下标不同的数使得他们的异或等于 x。
输入格式
输入的第一行包含三个整数 n,m,x。
第二行包含 n 个整数 A1,A2,⋅⋅⋅,An。
接下来 m 行,每行包含两个整数 li,ri 表示询问区间 [li,ri]。
输入
输入的第一行包含三个整数 n,m,x。
第二行包含 n 个整数 A1,A2,⋅⋅⋅,An。
接下来 m 行,每行包含两个整数 li,ri 表示询问区间 [li,ri]。
输出
对于每个询问,如果该区间内存在两个数的异或为 x 则输出 yes,否则输出 no。
样例
输入:
4 4 1
1 2 3 4
1 4
1 2
2 3
3 3
输出:
yes
no
yes
no
首先是暴力解法会超时
#include<iostream>
using namespace std;
const int N = 100010;
int n,m,x;
int q[N];
int main(){
scanf("%d%d%d",&n,&m,&x);
for(int i=1;i<=n;i++) scanf("%d",&q[i]);
while(m--){
int l,r;
scanf("%d%d",&l,&r);
bool flag = false;
for(int i =l;i<=r;i++){
for(int j=i+1;j<=r;j++){
if((q[i]^q[j])==x){
flag = true;
break;
}
}
}
if(flag) printf("yes\n");
else printf("no\n");
}
}
然后是优化后的解法
#include<iostream>
using namespace std;
const int N = 100010;
int n,m,x;
int g[N],last[1<<20];
int main(){
scanf("%d%d%d",&n,&m,&x);
for(int i=1;i<=n;i++){
int a;
scanf("%d",&a);
g[i] = max(g[i-1],last[x^a]);
last[a] = i;
}
while(m--){
int l,r;
scanf("%d%d",&l,&r);
if(g[r]>=l) puts("yes");
else puts("no");
}
}