题目
给定一个长度为 的数列 和一个非负整数 ,给定 次查询,每次询问能否从某个区间 中选择两个下标不同的数使得他们的异或等于 。
输入格式
输入的第一行包含三个整数 。
第二行包含 个整数 。
接下来 行,每行包含两个整数 表示询问区间 。
输出格式
对于每个询问,如果该区间内存在两个数的异或为 则输出 yes
,否则输出 no
。
数据范围
对于 的评测用例, ;
对于 的评测用例, ;
对于所有评测用例, , , , 。
输入样例:
4 4 1
1 2 3 4
1 4
1 2
2 3
3 3
输出样例:
yes
no
yes
no
样例解释
显然整个数列中只有 的异或为 。
解题
方法一:脑筋急转弯 动态规划
思路
首先,由异或运算的自反性我们可以得到 。
那么对于每个 ,如果存在 且 就说明在区间 内存在一对异或为 的数,我们自然可以在读入数组的同时预处理每个 找到离它最近且小于它且满足以上条件的 存入哈希表,然后对于每个查询枚举区间 在哈希表中查询是否有满足条件的一对。但是这样的话每次查询的时间复杂度是 ,总时间复杂度是 ,会超时。
定义 : 且 且 为满足以上两个条件时离 最近的下标(不存在则为 ),因为 所以 必定小于 且如果 那么 也一定小于 ,所以 可以扩大范围从 中找(因为如果 小于 非法,那么找出的 一定也因为小于 而非法,不会出现非法 找出合法 的情况),维护 ,如果 就说明区间 有满足条件的一对。这样以来就把查询的时间复杂度降到了 ,总时间复杂度为 。
以动态规划的角度理解:
- 状态定义: 表示 中一对异或为 的数中较小的数的最大值。
- 状态转移方程: ( 定义如上)。
- 初始状态:。
代码
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
in.nextToken();
int n = (int) in.nval;
in.nextToken();
int m = (int) in.nval;
in.nextToken();
int x = (int) in.nval;
int[] dp = new int[n + 1];
Map<Integer, Integer> latest = new HashMap<>();
for (int i = 1; i <= n; ++i) {
in.nextToken();
int a = (int) in.nval;
dp[i] = Math.max(dp[i - 1], latest.getOrDefault(a ^ x, 0));
latest.put(a, i);
}
while (m-- > 0) {
in.nextToken();
int l = (int) in.nval;
in.nextToken();
int r = (int) in.nval;
System.out.println(dp[r] >= l ? "yes" : "no");
}
}
}
评论区