位运算技巧

位运算是状态压缩DP的基础。

算符

C/C++中的位运算算符(按优先级排序):

红色算符与位运算算符的优先级高低顺序容易弄混,这里强调一下。

~ (bitwise NOT) 按位非 ~x

*  /  %

+ -

>  >=  <  <=

<<  >> (bitwise left shift and right shift) 按位左移、右移 x>>y  x>>=y

== !=

& (bitwise AND) 按位与 x&y  x&=y

^ (bitwise XOR) 按位异或 x^y  x^=y

| (bitwise OR)    按位或 x|y  x|=y

基本操作

1、判断x的第i位      x & 1<<i

2、将x的第i位置0    x & ~(1<<i)

3、将x的第i位置1    x | 1<<i

4、求x的最低位的1           lowbit(x)  x & -x

枚举子集

我们知道,可以用一个整型(例如 int、long long)变量 $s$ 表示一个大小不超过该整型位数的全集 $U$ 的某个子集 $S$。现在考虑如何枚举一个用整数 $s$ 表示的集合的所有子集。首先 $s$ 的子集的值必不大于 $s$,所以可以举 $[0,s]$ 的整数,判断其是否为 $s$的子集,复杂度为 $O(s)$。还有一种更好的做法,复杂度为$s$ 的子集个数。

for(int s=u; ; s=(s-1)&u){
  // do something with s
  if(s == 0) break;
}

 枚举大小为 $k$ 的子集

注意:要求 $k > 0$。

int comb = (1 << k) - 1;
while (comb < 1 << n) {
    // do sth with comb
    int x = comb & -comb, y = comb + x;
    comb = ((comb & ~y) / x >> 1) | y;
}

 枚举超集

for (int s = u; s <= tot; s = (s + 1) | u) {
    // do something with s
}

 

posted @ 2015-05-03 16:24  Pat  阅读(220)  评论(0编辑  收藏  举报