C. Mikasa
题目传送门:
题面:
题目大意:
这什么位运算场。
给你
n
,
m
n,m
n,m,让你求
n
⊕
0
,
n
⊕
1...
n
⊕
m
{n⊕0,n⊕1...n⊕m}
n⊕0,n⊕1...n⊕m中最小未出现的非负数。
运算法则:
a ⊕ a = 0
a ⊕ b = b ⊕ a(交换律)
a ⊕b ⊕ c = a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c; (结合律)
d = a ⊕ b ⊕ c 可以推出 a = d ⊕ b ⊕ c.
a ⊕ b ⊕ a = b.
A ⊕ 0 = A ;
1异或任何数,其结果=任何数取反;
任何数异或自己,等于把自己置0
思路:
如果存在y,
n
⊕
x
=
y
n⊕x=y
n⊕x=y,
0
≤
x
≤
m
0≤x≤m
0≤x≤m。
可以转化
n
⊕
x
=
y
n⊕x=y
n⊕x=y 为
n
⊕
y
=
x
n⊕y=x
n⊕y=x。
0
≤
x
≤
m
0≤x≤m
0≤x≤m。
所以原问题,找最小非负且不为y的数。
转化为找到最小的非负k,满足
n
⊕
k
≥
m
+
1
n⊕k≥m+1
n⊕k≥m+1
设m+1=p;
找
n
⊕
k
≥
p
n⊕k≥p
n⊕k≥p!!!
考虑从高位往低位构造。
- n i = = p i n_i==p_i ni==pi则 k i = 0 k_i=0 ki=0,保证 n i = = p i n_i==p_i ni==pi,也可以达成 n = = p n==p n==p。
-
n
i
=
1
,
p
i
=
0
n_i=1,p_i=0
ni=1,pi=0则
k
i
=
0
k_i=0
ki=0即可。此时已满足
n
i
⊕
k
i
(
1
)
≥
p
i
(
0
)
n_i⊕k_i(1)≥p_i(0)
ni⊕ki(1)≥pi(0),直接进行一个
break
- n i = 0 , p i = 1 n_i=0,p_i=1 ni=0,pi=1,则此时 k i k_i ki必须==1,否则结果的这一位就比p的这一位小了,之后一定 n ⊕ k ≤ p n⊕k≤p n⊕k≤p。
想通了还是不难的。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n >> m;
if (m + 1 <= n) {
//0异或a=a
//要找到最小k,满足n异或k≥m+1
//也就是满足n异或k>m
cout << 0 << endl;
continue;
}
m++;
int k = 0;
for (int i = 30; i >= 0; i--) {
int x = n >> i & 1;
int y = m >> i & 1;
//取二进制每一位
if (x == y) continue;
//k这一位为0;
if (y) {
k ^= 1 << i;
n ^= 1 << i;
//k这一位为1
}
if (n >= m) break;
//n存了结果
}
cout << k << endl;
}
return 0;
}
他人代码
while (T--) {
int n, m;
cin >> n >> m;
int ans = 0;
m++;
for (int i = 30; i >= 0; i--) {
if (((1 << i) & m) && !((1 << i) & n))ans += 1 << i;
//更简洁,pi==1&&ni==0,那么ki==1;
//否则后面几位变化改变不了高位已经比p小
else if (!((1 << i) & m) && ((1 << i) & n))break;
//一样直接不处理
//pi==0&&ni==1,满足条件了,跳出就行。
}
cout << ans << endl;
}