📌  相关文章
📜  给定操作生成的序列中第N个二进制字符串中的第M位(1)

📅  最后修改于: 2023-12-03 15:41:16.812000             🧑  作者: Mango

给定操作生成的序列中第N个二进制字符串中的第M位

假设有一个由 $0$ 和 $1$ 组成的字符串序列,初始字符串为 $0$。每一步操作都是从当前字符串复制出两份,然后在一份字符串的开头加上 $0$,在另一份字符串的开头加上 $1$,然后将这两份字符串拼接起来形成新的字符串。

例如,第一步操作后得到的字符串为 $01$,第二步操作后得到的字符串为 $0011$ 和 $0110$,第三步操作后得到的字符串为 $000111$、$001011$、$010011$ 和 $011110$。

给定操作次数 $n$,以及要求的字符串在生成序列中的下标 $m$,请你输出生成的序列中第 $n$ 个字符串中的第 $m$ 位字符。

解法

由于操作是以当前的字符串复制出两份并加上固定的字符得到的,我们可以发现:

  • 第 $i$ 步操作会生成 $2^{i-1}$ 个字符串;
  • 第 $i$ 步操作生成的第 $j$ 个字符串的第 $k$ 位,等价于将 $j$ 表示成二进制后的第 $k+1$ 位(从右往左数)。

例如,第三步操作生成的字符串为:

000111 001011 010011 011110

将它们的下标 $0,1,2,3$ 的二进制表示分别写出来:

000   001   010   011

可以发现,第 $k+1$ 位为 $1$ 表示 $k$ 在二进制下的第 $k+1$ 位为 $1$。

因此,我们可以从 $n$ 的二进制表示出发,取出每一位,判断对应的子串是否包含第 $m$ 个字符,然后依次计算出答案。

注意,第 $n$ 步操作生成的下标范围为 $[2^{n-1},2^n-1]$,因此当 $m$ 不在这个范围内时,直接输出 $0$。

代码
def get_bit_at_pos(n: int, m: int) -> int:
    if not (2 ** (n-1) <= m <= 2 ** n - 1):
        return 0
    ans = 0
    for i in range(n):
        if ((m - 2 ** (n-1)) >> i) & 1:
            ans ^= 1
    return ans

该函数的输入为 $n$ 和 $m$,输出为生成的序列中第 $n$ 个字符串中的第 $m$ 位字符。