进制位技巧总结
进制位骚操作总结
lowbit
最低的为 \(1\) 的二进制位。
x&-x
利用负数二进制存储为补码的性质,我们知道负数补码是按位取反后+1,也就是原来最低的连续的一段 \(0\) 会疯狂进位直到遇到第一个 \(1\) ,和原数按位与一下就可以了。
highbit
最高的为 \(1\) 的二进制位。
预处理 \(lg2\) 数组或者使用 \(\_\_lg()\) 函数。不要用 \(log2()\) ,有 \(O(\log n)\) 的常数。
k bit状态压缩
用二进制存储集合和状态的操作大家都知道吧。显然 \(k\) 进制也是可以的。
预处理 \(k\) 的幂次可以实现快速操作。
举一个 4 bit 的例子:
struct fourbit{
fourbit(int _x){
x=_x;
}
int x;
inline int pos(int p){
return (x/pw[p])%4;
}
inline void set(int p,int k){
x=x+(k*pw[p])-(pos(p)*pw[p]);
}
};
集合除去
x&(x^k)
在保证 \(k\subset x\) 的情况下, 异或将 \(k\) 从 \(x\) 中除去吗。但是如果不保证,我们可以通过与运算把误增加的元素除去。
枚举子集
for(int x=s;x;x=(x-1)&s)
这样就可以遍历 \(s\) 的子集。你发现每次子集的十进制数单调降,并且不会错过任何一个子集。因为每次把最低的 \(1\) 拉下来。需要注意的是,这个方法不会枚举到空集,需要特判一下。
通过三进制分析,枚举一个集合及其子集是 \(O(3^n)\) 的。
后续会持续更新。