• 浅谈lowbit运算


    关于lowbit运算的相关知识

    本篇随笔简单讲解一下计算机中位运算的一类重要运算方式——(lowbit)运算。

    lowbit的概念

    我们知道,任何一个正整数都可以被表示成一个二进制数。如:

    [(2)_{10}=(10)_2 ]

    [(4)_{10}=(100)_2 ]

    [cdots ]

    那么定义一个函数(f=lowbit(x)),这个函数的值是(x)的二进制表达式中最低位的(1)所对应的值。

    比如:

    [(6)_{10}=(110)_2 ]

    那么(lowbit(6))就等于(2),因为((110)_2)中最低位(就是从右往左数的第二位)对应的数是(2^1=2)

    所以假设一个数的二进制最低位的(1)在从右往左数的第(k)位,那么它的(lowbit)值就是

    [2^{k-1} ]

    lowbit函数的实现

    lowbit函数实现有两种方式:

    一、

    x&(x^(x-1))

    二、

    x&-x

    简单解释一下:

    我们得到lowbit的值,只需要得到最后一个1的位置,并且把除了这个位置之外的所有位置全部置成零。然后输出就可以。

    那么我们看一看x&(x^(x-1))

    拿上面的6举例:

    [(110)_2-1=(101)_2 ]

    我们发现,根据小学数学减法运算的借位原则(滑稽),对一个二进制数进行减1,那么会出现从这个这个数的最后一个1开始到最后的所有数都取反,即构成一个(01111cdots)的串。

    我们把这个数与原数异或,就会造成:第一个1以后的数(包括第一个1)全部取1.其他的位全部取0.即构成一个由一堆0后面跟一堆1的串。

    那么再把原式做一个与运算,那么除了原来的那个1(对应位都是1)为1,其他位全是0,完成任务。

    那么我们再看一看x&-x

    根据计算机补码的性质。

    补码就是原码的反码加一

    如:

    [(110)_2=6 ]

    反码:

    [(001)_2 ]

    加一:

    [(010)_2 ]

    可以发现变为反码后 x 与反码数字位每一位都不同, 所以当反码加1后神奇的事情发生了,反码会逢1一直进位直到遇到0,且这个0变成了1,所以这个数最后面构造了一个 100… 串。 由于是反码,进位之后由于1的作用使进位的部分全部取反及与原码相同,所以可以发现 lowbit 以前的部分 x 与其补码即 -x 相反, lowbit x 与 -x 都是1,lowbit 以后 x 与 -x 都是0 所以 x&-x 后除了 lowbit 位是1,其余位都是0。符合条件。

    用lowbit运算统计1的个数

    我们可以使用lowbit运算统计一个整数的二进制形式下1的个数。

    实现原理很简单啦,就是:我们先用lowbit运算找出(lowbit(x)),然后用原数减去这个数,依次循环,直到为0为止。

    这也是树状数组的实现原理。

    代码:

    while(x)
    {
    	x-=x&-x;
    	ans++;
    }
    

    (巨短无比)

    lowbit运算的应用

    关于lowbit运算,最著名的应用应该算是树状数组。但是lowbit的神妙远远不止树状数组,在很多二进制和位运算的相关题目中,都有lowbit运算的影子。甚至,在状态压缩DP中,lowbit也扮演着一份不可忽视的角色。

  • 相关阅读:
    虚树
    最小树形图
    分块
    斜率优化
    单调队列优化DP
    树套树
    2-SAT
    莫队
    单调队列
    单调栈
  • 原文地址:https://www.cnblogs.com/fusiwei/p/11752540.html
Copyright © 2020-2023  润新知