给定一个长度为 n n n 的数列 A 1 , A 2 , ⋅ ⋅ ⋅ , A n A_{1},A_{2},⋅⋅⋅,A_{n} A1,A2,⋅⋅⋅,An 和一个非负整数 x x x,给定 m m m 次查询,每次询问能否从某个区间 [ l , r ] [l,r] [l,r] 中选择两个数使得他们的异或等于 x x x。
输入格式
输入的第一行包含三个整数
n
,
m
,
x
n,m,x
n,m,x。
第二行包含 n n n 个整数 A 1 , A 2 , ⋅ ⋅ ⋅ , A n A_{1},A_{2},⋅⋅⋅,A_{n} A1,A2,⋅⋅⋅,An 。
接下来 m m m 行,每行包含两个整数 l i , r i l_{i},r_{i} li,ri 表示询问区间 [ l i , r i ] [l_{i},r_{i}] [li,ri]。
输出格式
对于每个询问,如果该区间内存在两个数的异或为
x
x
x 则输出 yes
,否则输出 no
。
数据范围
对于
20
20%
20 的评测用例,
1
≤
n
,
m
≤
100
1≤n,m≤100
1≤n,m≤100;
对于
40
40%
40 的评测用例,
1
≤
n
,
m
≤
1000
1≤n,m≤1000
1≤n,m≤1000;
对于所有评测用例,
1
≤
n
,
m
≤
100000
,
0
≤
x
<
220
,
1
≤
l
i
≤
r
i
≤
n
,
0
≤
A
i
<
220
1≤n,m≤100000,0≤x<220,1≤l_{i}≤r_{i}≤n,0≤A_{i}<220
1≤n,m≤100000,0≤x<220,1≤li≤ri≤n,0≤Ai<220。
题解
-
a
⊕
b
=
x
⟺
a
⊕
b
⊕
x
=
0
⟺
a
⊕
x
=
b
a⊕b=x⟺a⊕b⊕x=0⟺a⊕x=b
a⊕b=x⟺a⊕b⊕x=0⟺a⊕x=b
因此对于一个数 a a a, 与 a a a配对的数可以直接计算得出, 即为 a ⊕ x a⊕x a⊕x - 使用闫氏DP分析法:
代码实现
用哈希表
l
a
s
t
[
X
]
last[X]
last[X]记录数值X
最后一次出现时的位置下标, dp[i]
的求法是: 若
a
i
⊕
x
a_{i}⊕x
ai⊕x最后一次出现的下标要大于dp[i-1], 则
d
p
[
i
]
=
l
a
s
t
[
a
i
⊕
x
]
dp[i] = last[ai⊕x]
dp[i]=last[ai⊕x], 否则
d
p
[
i
]
=
d
p
[
i
−
1
]
dp[i] = dp[i-1]
dp[i]=dp[i−1]
即
d
p
[
i
]
=
m
a
x
(
d
p
[
i
−
1
]
,
l
a
s
t
[
a
i
⊕
x
]
)
dp[i]=max(dp[i−1],last[a_{i}⊕x])
dp[i]=max(dp[i−1],last[ai⊕x])
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int dp[N], n, m, x;
int main() {
cin >> n >> m >> x;
unordered_map<int, int> last;
for(int i=1; i<=n; i++) {
int a; cin >> a;
dp[i] = max(dp[i-1], last[x ^ a]);
//这句应该放到后面, 否则当x=0时会不正确(当x等于0时dp[i] = i, 但是要选两个不同位置的数)
//更正于2023/01/01
last[a] = i;
}
while (m -- ) {
int l, r; cin >> l >> r;
cout << (dp[r] >= l ? "yes" : "no") << endl;
}
return 0;
}