2018-03-16
异或的性质
- 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.
6.若x是二进制数0101,y是二进制数1011;
则x⊕y=1110
有上述性质,对于区间异或和要知道如下性质:
XOR[l,r] = XOR[1,l-1] ^ XOR[1,r]
异或的知识还有很多有趣的解释和应用,详情可以移步知乎。
(CodeForces - 948D)Perfect Security
题意:先给你一串数字a[n],然后再给你一串数字b[n],让你任意排列b[n],使得a[i]^b[i]的值的输出字典序最小。
思想:想办法让一个数字k异或后的结果最小,其实就是想办法让该数字二进制高位变为0,而由上面异或的性质可以知道,其实就是在另一串数字中找到一个数字d,使得数字d的二进制与数字k的二进制在高位上尽可能多得相同,于是就有了两个方法。
方法一:暴力寻找(??)
for(ll i=1<<30;i;i>>=1){
ans+=(i&x);
multiset::iterator it=S.lower_bound(ans);
if(it==S.end() || *it>=ans+i){
ans^=i;
}
}
S.erase(S.find(ans));
从x的高位找,如果a[n]中的数字最大值还不能达到高位,或者大于x的最小数字在二进制中甚至比x还高一位,那么异或取消。
还有一个有趣的一点就是:怎么确认我找到的ans一定是在b[n]呢——其实关键点就在lower_bound这里,举个例子就能理解。
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
方法二:常规01字典树。O(n*32(字典树深度))
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include