第十六届蓝桥杯省赛Python研究生组-F串

  • 考点:二分查找 + 数位统计
  • 题目描述:
  • 解题思路1:挨个统计
python 复制代码
import sys


def main():
    x = int(sys.stdin.readline().strip())
    total_1 = 0  # 统计1的总个数
    total_len = 0  # 已经拼接的总长度
    num = 0  # 从0开始拼接!

    while total_len < x:
        # 1. 把当前数字转成二进制字符串(去掉0b)
        binary = bin(num)[2:]
        # 2. 还能截取多少位:最多取到x位,不超额
        need = x - total_len
        # 3. 截取当前二进制的前 need 位
        cut = binary[:need]
        # 4. 统计这一段里的1,加到总数
        total_1 += cut.count('1')
        # 5. 更新总长度
        total_len += len(cut)
        # 6. 下一个数字
        num += 1

    return total_1


# 主程序
if __name__ == "__main__":
    main()
  • 解题思路2:

目标:前 n 位里有多少个 1

问题拆分:定位 + 统计

  1. 定位,前 n 位是**"哪些完整数字的二进制" + "最后一个不完整数字的前 offset 位"**

如何定位?------二分查找:找到最大的数字 target,使得前 target 个数字的二进制总长度 < n

  1. 统计,"完整数字中 1 的总数" + "最后一个数字前 offset 位中 1 的个数"

如何统计?------数位贡献:各数字二进制的第 i 位,每 个数为一个周期,每个周期中有 个 1,且前半周期是 0,后半周期是 1

  • 核心函数思路:返回 [0,n] 拼接成二进制串后的长度和其中 1 的个数
  1. 总长度

按位分段:除了0以外,二进制有1位的有 个数字、2位的有 个、3位的有 个、4位的有 个、...k位的有 个,这个值也表示二进制有k位的最小数字 ,则二进制有k位的数字总长度为 × k

知道这个规律后,可以先获取数字 n 的二进制位数 bits_count,然后累加计算 1 到 bits_count-1 位的总长度

python 复制代码
    bits_count = n.bit_length()

    for i in range(1, bits_count):
        # i位二进制数的个数
        cur_num = 2 ** (i-1)
        length += cur_num * i

接着计算位数为 bits_count,到数字 n 截止的长度

python 复制代码
# 截止到 n 的 bits_count 位的数字个数
now_num = n - (2 ** (bits_count - 1)) + 1
length += now_num * bits_count
  1. 含1个数

数位贡献:根据前文分析,累加计算各周期中1的个数

python 复制代码
bits_count = n.bit_length()
    for i in range(bits_count):
        # 周期长度 = 2^(i+1)
        period = 2 ** (i+1)
        # 每个周期内第i位为1的次数 = 2^i
        period_count = 2 ** i
        # 完整周期数
        full = (n+1) // period
        count += full * period_count
        # 不完整周期的有效个数
        not_full = (n+1) % period
        if not_full > period_count:
            count += (not_full - period_count)
  • 参考代码:
python 复制代码
import sys



# 计算数字[0,n)拼接成二进制串后的长度,以及其中1的个数
def get_info(n):
    if n <= 0:
        return 0,0
    if n == 1:
        return 1,0

    m = n - 1
    length = 1
    count = 0

    # 统计1的个数,数位贡献
    # m的二进制位数
    bits_count = m.bit_length()
    for i in range(bits_count):
        # 周期长度 = 2^(i+1)
        period = 1 << (i+1)
        # 每个周期内第i位为1的次数 = 2^i
        period_count = 1 << i
        # 完整周期数
        full = (m+1) // period
        count += full * period_count
        # 不完整周期的有效个数
        not_full = (m+1) % period
        if not_full > period_count:
            count += (not_full - period_count)

    # 统计总长度,按位数分段,遍历i~bits_count-1位
    for i in range(1, bits_count):
        # i位二进制数的个数
        cur = 1 << (i-1)
        length += cur * i
    # 计算bits_count位的数字个数
    cur = m - (1 << (bits_count - 1)) + 1
    length += cur * bits_count

    return length, count

def main():
    x = int(sys.stdin.readline().strip())
    if x == 1:
        print(0)
        return

    # 二分查找定位目标数字:找到第 x 位在哪个数字 target 的二进制中
    # 逻辑:找最大的 target,使得前 target 个数字的长度<x
    left = 1
    # 将x作为上界
    right = x
    target = 0
    while left <= right:
        mid = (left + right) // 2
        # 取[0,mid)的总长度,忽略1的个数,_表示占位符
        length, _ = get_info(mid)
        if length < x:
            # 总长度不足,mid符合条件,目标在更大的数字里
            target = mid
            left = mid+1
        else:
            # 长度超过或与x相等,缩小上界
            right = mid-1
    # 二分查找完毕,此时target是最后一个总长度小于x的数字

    len1, sum1 = get_info(target)
    offset = x - len1
    bin_target = bin(target)[2:]

    ans = sum1 + bin_target[:offset].count('1')
    print(ans)

if __name__ == '__main__':
    main()
  • 位运算:1 << k,等同于

原理:二进制中左移一位,本质上就是乘以2

最好用位运算而不是幂运算 ** :位运算是 CPU 底层直接支持的硬件指令,速度快,而幂运算本质上是一个函数调用

相关推荐
Li emily8 小时前
解决了加密货币api多币种订阅时的数据乱序问题
人工智能·python·api·fastapi
csdn_aspnet8 小时前
C语言 Lomuto分区算法(Lomuto Partition Algorithm)
c语言·开发语言·算法
2301_781571428 小时前
Golang格式化输出占位符都有什么_Golang fmt占位符教程【通俗】
jvm·数据库·python
asdzx678 小时前
使用 Python 为 PDF 添加页码 (详细教程)
python·pdf·页码
谙弆悕博士8 小时前
【附C源码】从零实现C语言堆数据结构:原理、实现与应用
c语言·数据结构·算法··数据结构与算法
AI技术控9 小时前
《Transformers are Inherently Succinct》论文解读:从“能表达什么”到“多紧凑地表达”
人工智能·python·深度学习·机器学习·自然语言处理
金融大 k11 小时前
Python 全球指数监控面板:TickDB + REST + WebSocket 完整方案
python·websocket
啊哈哈1213811 小时前
系统设计复盘:为什么 Agent 的 ReAct 循环必须内嵌确定性保护层——以 FitMind 健康助手的路由与步骤控制为例
人工智能·python·react
gaosushexiangji11 小时前
DIC系统推荐:基于千眼狼三维数字图像相关的无人机旋翼疲劳试验全场应变与位移测量
人工智能·算法
一颗牙牙12 小时前
安装mmcv
开发语言·python·深度学习