位运算
位运算
功能 |
示例 |
位运算 |
去掉最后一位 |
(101101->10110) |
x >> 1 |
在最后加一个0 |
(101101->1011010) |
x << 1 |
在最后加一个1 |
(101101->1011011) |
x << 1+1 |
把最后一位变成1 |
(101100->101101) |
x | 1 |
把最后一位变成0 |
(101101->101100) |
x | 1-1 |
最后一位取反 |
(101101->101100) |
x ^ 1 |
把右数第k位变成1 |
(101001->101101,k=3) |
x | (1 << (k-1)) |
把右数第k位变成0 |
(101101->101001,k=3) |
x & !(1 << (k-1)) |
右数第k位取反 |
(101001->101101,k=3) |
x ^ (1 << (k-1)) |
取末三位 |
(1101101->101) |
x & 7 |
取末k位 |
(1101101->1101,k=5) |
x & (1<< k -1) |
取右数第k位 |
(1101101->1,k=4) |
x >> (k-1) & 1 |
把末k位变成1 |
(101001->101111,k=4) |
x | (1 << k-1) |
末k位取反 |
(101001->100110,k=4) |
x ^ (1 << k-1) |
把右边连续的1变成0 |
(100101111->100100000) |
x & (x+1) |
把右起第一个0变成1 |
(100101111->100111111) |
x | (x+1) |
把右边连续的0变成1 |
(11011000->11011111) |
x | (x-1) |
取右边连续的1 |
(100101111->1111) |
(x ^ (x+1)) >> 1 |
去掉右起第一个1的左边 |
(100101000->1000) |
x & (x ^ (x-1)) |
去掉最后一位 |(101101->10110) | x >> 1
在最后加一个0 |(101101->1011010) | x < < 1
在最后加一个1 |(101101->1011011) | x < < 1+1
把最后一位变成1 |(101100->101101) | x | 1
把最后一位变成0 |(101101->101100) | x | 1-1
最后一位取反 |(101101->101100) | x ^ 1
把右数第k位变成1 | (101001->101101,k=3) | x | (1 < < (k-1))
把右数第k位变成0 | (101101->101001,k=3) | x & ~ (1 < < (k-1))
右数第k位取反 | (101001->101101,k=3) | x ^ (1 < < (k-1))
取末三位 | (1101101->101) | x & 7
取末k位 | (1101101->1101,k=5) | x & ((1 < < k)-1)
取右数第k位 | (1101101->1,k=4) | x >> (k-1) & 1
把末k位变成1 | (101001->101111,k=4) | x | (1 < < k-1)
末k位取反 | (101001->100110,k=4) | x ^ (1 < < k-1)
把右边连续的1变成0 | (100101111->100100000) | x & (x+1)
把右起第一个0变成1 | (100101111->100111111) | x | (x+1)
把右边连续的0变成1 | (11011000->11011111) | x | (x-1)
取右边连续的1 | (100101111->1111) | (x ^ (x+1)) >> 1
去掉右起第一个1的左边 | (100101000->1000) | x & (x ^ (x-1))
判断奇数 (x&1)==1
判断偶数 (x&1)==0
取右边第一个1所在位置 x&-x
0/1枚举问题
假设有n个杯子,每个杯子里都装有不同的数量的钱,你可以任意的选择其中的任意数量个杯子带走,请问你有多少种不同收获结果?
思路
每一个杯子都有选择或者不选择两种状态,在不考虑复杂度的情况下,可以进行2^n次枚举,获取每一种情况下的结果!
那么如何实现对2^n中情况下的枚举呢????
考虑,对于数 0 ~2^n-1,任意两个不同的数的二进制表示都是不同的,他们每一位的0或1可以表示为该编号的水杯被选择或不被选择,而且要表示2^n-1恰好需要n位!
for(int i =0; i<(1<<n); i++) //将1左移n位,其值为2^n { int cot =0; //初始金钱 for( int j =0; j<n; j++) { if(i&(1<<j)) // 在当前的情况下,第j个杯子是否被选中呢?即i的第j位是不是1? cot+= val[j]; } cout<< i <<":"<<cot<<endl; //输出第i种情况下的值 }
二进制枚举子集
#include<bits/stdc++.h> using namespace std; const int N=2010; int n,m,ans1,ans2,ans3,mp[N][N],u[N],v[N]; int main() { int n; cin >> n; for(int i=0; i<(1<<n); i++) { for(int j=0; j<n; j++){ if(i&(1<<j)){ cout << j ; } } cout<<endl; } return 0; } /* 3 [0 1 2] 空 0 /1 /2 0 1/0 2 1 2 0 1 2 ------------------- 0 1 01 2 02 12 012 */
1.判断一个数字x在二进制下第i位是不是等于1。 方法:if ( ( ( 1 << ( i - 1 ) ) & x ) >0) 解析:将1左移i-1位,相当于制造了一个只有第i位上是1, 其他位上都是0的二进制数,然后用该数与x做与运算, 如果结果>0,说明x第i位上是1,反之则是0。 2.把一个数字x在二进制下的第i位更改成1。 方法:x |= ( 1<<(i-1) ) 证明方法与1类似(将1左移i-1位,相当于制造了一个只有第i位上是1, 其他位上都是0的二进制数,然后用该数与x做或运算,只要存在1就为1, 所得结果即为新的x值 当(x&(x<<1))为真 时说明有玉米相邻