题目
给定一个长度为 n 的数列 A1,A2,···,An 和一个非负整数 x,给定 m 次查询,每次询问能否从某个区间 [l,r] 中选择两个下标不同的数使得他们的异或等于 x。
输入格式
输入的第一行包含三个整数 n,m,x。
第二行包含 n 个整数 A1,A2,···,An。
接下来 m 行,每行包含两个整数 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
解题思路
1、关于异或
a ⊕ b = c ⟺ a ⊕ c = b
因此对于一个数,其对应的数可以直接计算得出,即为a⊕x
2、动态规划数组含义
将两个配对的数a,b简称为数对
定义dp[i]为区间[1,i]中所有数对中的最大下界
当查询区间[l,r]右边界为r时,至少包含一个数对时的左边界最大值,所以如果l小于左边界最大值(dp[r]),[l,r]内至少有一个数对
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, m, x;
int dp[N];
unordered_map<int, int> last;
int main() {
cin >> n >> m >> x;
for (int i = 1, a; i <= n && cin >> a; ++ i) {
dp[i] = max(dp[i - 1], last[a ^ x]);
last[a] = i;
}
while (m -- ) {
int l, r;
cin >> l >> r;
cout << (dp[r] >= l ? "yes" : "no") << endl;
}
}
本篇博客代码主要参考于文章: