项目场景:
较难的dp+哈希 思维题
问题描述
给定一个长度为 n 的数列 A1,A2,···,An 和一个非负整数 x,给定 m 次查询,每次询问能否从某个区间 [l,r] 中选择两个数使得他们的异或等于 x。
输入格式
输入的第一行包含三个整数n,m,x。
第二行包含 n 个整数 A1,A2,···,An。
接下来 m 行,每行包含两个整数 li,rili,ri 表示询问区间 [li,ri][li,ri]。
输出格式
对于每个询问,如果该区间内存在两个数的异或为 x 则输出 yes
,否则输出 no
。
数据范围
对于 20% 的评测用例,1≤n,m≤100;
对于 40% 的评测用例,1≤n,m≤1000;
对于所有评测用例,1≤n,m≤100000,0≤x<220,1≤li≤ri≤n,0≤Ai<220。
输入样例:
4 4 1
1 2 3 4
1 4
1 2
2 3
3 3
输出样例:
yes
no
yes
no
样例解释
显然整个数列中只有 2,3 的异或为 1。
原因分析:
题目是在指定的一段区间内判断区间内是否存在一个数与指定的数异或的值为x
考虑dp f[i] 存储的为与a[i]异或的数的下标值 区间为[l,r] l<=i<=r l<=f[i]<i<=r 要满足题目要求 则判断f[r]与l的关系即可 只要保证f[r]>=l 则一定存在匹配 具体见代码
实现代码:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<unordered_map>
using namespace std;
const int N = 1e6+10;
int f[110];
int a[N];
int n,m,x;
unordered_map<int,int> last;
int main(){
//读入数据部分
cin>>n>>m>>x;
for(int i=1;i<=n;i++) cin>>a[i];
//进行dp
//这里的f[i] 表示与a[i]匹配的最近的数的下标
//last[a[i]^x] 表示与a[i]匹配的数最后一次出现的下标
for(int i=1;i<=n;i++){
f[i] = max(f[i-1],last[a[i]^x]);
last[a[i]] = i;
}
while(m--){
int l,r;
cin>>l>>r;
//只需要区间的右端点对应的f[i]存储的下标大于左端点 则说明在指定区间内存在一个数能够与给定数匹配
if(f[r]>=l) cout<<"yes"<<endl;
else cout<<"no"<<endl;
}
return 0;
}