位运算相关技巧
主要是状态压缩中会遇到的一些问题。
基础运算
- 与 ($\ \&\ $):有0就0
- 或 ($\ |\ $):有1就1
- 异或 (^ 或者 \(xor\)):同0异1
- 非(取反) ( ~ ) :0变1,1变0
注意:在符号型整数\((int,long\ long)\)下进行按位取反运算会使得最高位(也就是符号位)也取反,并使数值加1,如\(\\~6=-7\).
联系应用
按位位运算的特点:独立性,即只改变整数二进制表示下的某位,并不影响其他位.
异或:常与trie(字典树)结合,把整数二进制表示下的各位压进trie上,在trie上进行按位操作. 如:最大异或对,最长异或路径
初始化
空位赋值为1
常见的状压都是通过用‘1’来表示节点已使用,但也有些题会结合lowbit,让我们把空位设为‘1’以取出能用的空位.(如:数独)
我们可以采用以下初始化方法:
n=(1<<x)-1
以此将n的左x位全设为1.
memset
- 赋值为正无穷:
memset(f,0x3f,sizeof(f));
- 赋值为负无穷:
memset(f,0c3f,sizeof(f));
状压操作
对于一个整数n的二进制表示(^为异或):
- 取出第k位
(n>>k)&1
- 取出后k位 (与初始化类似的思想)
n&((1<<k)-1)
- 第k位按位取反
n=n^(1<<K)
- 第k位赋值为1
n=n|(1<<K)
- 第k位赋值为0
n=n&(~(1<<K))
lowbit
lowbit(n)表示取出n在二进制表示下最低位的‘1’及其后面的0.
如:\(6_{(10)}=110_{(2)}\),则\(lowbit(6)=10_{(2)}=2_{(10)}\)
可以用来找出n在二进制表示下所有是‘1’的位,也是树状数组的基础.
- 具体操作:
$ lowbit(n) = n \& (-n) $
若要取出所有是‘1’的位的位置,则先用Hash预处理\(log_2\),使得\(lg[1<<x]=x\);如lowbit(n)取出\(100_{(2)}=1<<3\),则最低位的‘1’在第三位
注意:位置从0开始,如\(110_{(2)}\),最低位位置为1
每次取出lowbit(n)后减去它,使当前最低位的‘1’前移.
- 代码实现:
int n,lg[(1<<20)+1];
void lowbit()
{
for(int i=0;i<=20;i++) lg[1<<i]=i; //预处理
while(n){
cout<<lg[n&(-n)]<<endl;
//输出当前最低位‘1’的位置,如110(2)输出1
n-=n&(-n);
}
}

浙公网安备 33010602011771号