• 线性时间复杂度递推求 0 到 2的幂次-1 的二进制翻转


    如何定义一个数的二进制翻转(后的数)?
    也就是

    [reverse(quad (dots x_3x_2x_1x_0)_2 quad) = ; ? ]


    直观地理解, 就是把一个数的二进制表示的最后一位和第一位交换、倒数第二位和第二位交换……
    但是就如上面的例子, 知道了一个数二进制表示的最后一位, 那么这个数的二进制表示下的第一位是什么?不规定第一位, 翻转后的数是确定且唯一的吗?

    显然平常求一个数的二进制翻转, 是要求一个具体的数。
    要求具体的数, 就要规定一个数的 “二进制位数”, 意即这个数在二进制表示下的第一位是从右到左第几位。


    本文介绍的递推方法, 可以求二进制位数一定时的所有数的二进制翻转(显然有限的二进制位数只能表示有限个数, 即 (x) 位二进制只能表示 ([0, 2^x-1])(2^x) 个数)。

    (由于不是我想出来的所以只给方法啦qwq)

    具体方法是将一个二进制数 ((x_n dots x_0)_2) 看作 ((x_n dots x_1)_2)((x_0)_2)
    首尾相接拼起来的两个数, 于是

    [reverse(quad (x_n dots x_0)_2 quad) ]

    [= x_0 接上 ; reverse(quad (x_n dots x_1)_2 quad) ]

    (下面式子里的 (reverse(quad (x_n dots x_1)_2 quad)) 是在二进制位数为 (n) 意义下的翻转)

    但是递推到 ((x_n dots x_0)_2) 时, 手上只有 ((0:x_n dots x_1)_2)
    (即(x_n dots x_1)_2)在二进制位数为 (n+1) 意义下的表示)
    的二进制翻转, 怎么办?

    其实操作一番就是了, 具体看代码就好啦。

    最后一点就是由于 (x_0) 是二进制位数为 (n) 意义下的最后一位, 所以其必定被翻转到二进制位数为 (n) 意义下的第一位(帮助理解代码)。

    for(int i=0; i<lim; ++i) { // lim是二的幂次
    //这段代码是求 0 ~ lim-1 在二进制位数为 log_2(lim)-1 意义下的二进制翻转
    //其中, 数 i 的翻转被储存在 re[i] 里
    	re[i] = (re[i>>1]>>1)|((i&1)?lim>>1:0);
    }
    
  • 相关阅读:
    Hard 随机洗牌函数 @CareerCup
    Hard 随机选择subset @CareerCup
    Hard 计算0到n之间2的个数 @CareerCup
    Django admin进阶
    hdu 5630 Rikka with Chess
    PHP 表单验证
    PHP 表单验证
    PHP 表单验证
    PHP 表单验证
    PHP 表单处理
  • 原文地址:https://www.cnblogs.com/tztqwq/p/12774894.html
Copyright © 2020-2023  润新知