zoukankan      html  css  js  c++  java
  • 位运算

    其实位运算很好理解,又比较好用,状态分明,易于想象,反正不是1就是0

    还算轻松的开头


     基础算术位运算

    与  and  &:两者都为1则为1,其他情况都为0

    或    or    |:两者都为0则为0,其他情况都为1

    非  not   ~:对于一个二进制数,每位取反,0变为1,1变为0

    亦或 xor ^:两者相同则为0,不同则为1

    补码

    unsigned int:32位无符号整数  可以直接把32位编码看成32位二进制数

    int:32位有符号整数  最高位表示正负,0为正,1为负

    对于int型数,正数补码为它本身,负数补码为除符号位外所有位取反后再+1

    所以对于一个int数x,全部位取反后得到的数为-1-x

    已知补码求原码:

    如果补码的符号位为0,表示是一个正数,其原码就是补码。

    如果补码的符号位为1,表示是一个负数,那么求给定的这个补码的补码就是要求的原码。

     

    反码

    正数的原码、补码、反码都相同,都等于它本身

    负数的反码是,符号位不变,其余各位求反

    负数反码末位加上1就是补码


    注意点:

    对一个数取反是对这个数的补码取反

    电脑保存的二进制数都是它的补码,在补码下每个数都有唯一表示方式

    两个数值做加减法运算,实质上是它们的补码做最高位不进位的二进制加减法运算

    表示

    在写程序的时候,常用十六进制来表示一个数,共8个字符,每个字符代表二进制中4个位

    用“0x”开头,声明进制

    后面跟上代表四位二进制数的字符(0~9,A~F)

    例如:3  ->  000……0011  ->  0x00000003(0011对应的十六进制为3)

    虽然int型最大正整数应该是0x7FFFFFFF,但一般用0x3F3F3F3F来表示最大值

    移位运算

    左移

    在二进制表示下所有位的数同时向左移动,低位0填充,高位如果超过范围就舍弃

    易得:1<<n=2n  n<<1=2*n

    右移

    在二进制表示下所有位的数同时向右移动,低位超过范围舍弃,高位以符号位填充

    n>>1=n/2

    等于除以2向下取整,但整数/2在c++中实现为向零取整

    所以,正数右移1位和除以2相同,但负数就不一样。例:(-3)>>1==-2,(-3)/2=-1

    二进制状态压缩

    用二进制数表示状态,典型运用状态压缩dp

    取出整数n在二进制表示下的第k位     (n>>k)&1

    取出整数n在二进制表示下的第0~k-1位(即后k位)  n&((1<<k)-1)

    把整数n在二进制表示下的第k位取反    n^(1<<k)

    把整数n在二进制表示下的第k位赋值为1    n|(1<<k)

    把整数n在二进制表示下的第k位赋值为0    n&(~(1<<k))

    lowbit运算

    lowbit(x)指非负整数x在二进制表示下 最低位的1及后面所有的0构成的数

    lowbit(x)=x&(~x+1)=x&(-x)

    推导过程:

    设x的最低位1在第k位,则第0~k-1位都为0

    把x取反,则第k位为0,0~k-1位都为1,第k+1~最高位与之前相反

    再+1后,由于进位,第0~k-1位再次变为0,第k位变为1

    而+1操作对第k+1~最高位无影响,所以恰好与原数相比相反

    这个时候把操作后的数与x进行 和运算,则从第k+1~最高位都为0,得到答案

    即lowbit(x)=x&(~x+1)

    又由补码表示下可得~x+1=-n,所以lowbit(x)=x&(-x)

    找出整数二进制下所有是1的位

    用lowbit运算+Hash

    求lowbit(x)可以求出最低位为1的位置,再把x赋值为x-lowbit(x),可以求出下一个为1的位,反复直到x=0

    求出的lowbit(x)为一个最高位为1,其余位都为0的数,这个数一定是2的n次方,而这个n就是它的最高位数,即原x中的1在第n位中(注:k位二进制数,这里最低位表示为第0位,最高位表示为第k-1位)

    要确定n,用Hash存储,可以实现O(1)的询问

    预处理Hash数组,把2n存储为n,即Hash( 2n )=n

    举个例子:要求十进制数x=10的二进制下所有是1的位

    x=10=(1010)2    ->   lowbit(x)=(10)2=2    ->    Hash( lowbit(x) )=Hash( 2 )=1   ->   x=x-lowbit(x) 即x=8=(1000)2  ->   lowbit(x)=lowbit(8)=(1000)2=8   ->  Hash( lowbit(x) )=Hash( 8 )=3    ->  x=x-lowbit(x)=0  ->停止

    用Hash求出的标红的两个数1、3即为所求

    程序实现

    for(int i=0;i<=20;i++)    Hash[1<<i]=i;
    while(x)
    {
        printf("%d ",Hash[x&(-x)]);
        x-=x&(-x);
    }

    大致就是这些,位运算一般都是题目中的一部分辅助工具,不太会单独出现。

    参考  李煜东的《算法竞赛进阶指南》

  • 相关阅读:
    简单数列极限证明
    既然已经半退役了,就写点新东西吧
    快速幂(整数+实数)
    D. Constant Palindrome Sum 差分+思维
    排序网络
    ClickHouse数据同步
    C++ 复习
    使用mac查看iphone uuid方法
    15. 蓝绿发布导致需求不能验证
    通过反射获取对象的属性名、属性值
  • 原文地址:https://www.cnblogs.com/mgtnb/p/12891205.html
Copyright © 2011-2022 走看看