栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

清晰好理解-----2021 python 蓝桥杯决赛“二进制问题”也不是太难】

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

清晰好理解-----2021 python 蓝桥杯决赛“二进制问题”也不是太难】

废话不多说,直接上代码
n, k = map(int, input().split())
bstr = str(bin(n))[2:]


def Cn(m, n):
    # 这个判断代表:当剩余二进制位数小于所需k值,即就算剩下的所有位都置1,依然无法满足条件
    if n < m:
        return 0
    # A计算
    a = 1
    for i in range(n, (n - m), -1):
        a *= i
    # 阶乘计算
    t = 1
    for i in range(1, m + 1):
        t *= i
    # C计算
    return a / t


cnt = 0
for i in range(0, len(bstr)):
    if k == 0:
        cnt += 1
        break
    if bstr[i] == '1':
        plus = int(Cn(k, len(bstr) - i - 1))
        # 下面这步判断代表:当所需k值<=剩余二进制位数时,是直接退出或是cnt+1退出
        if plus == 0:
            #  当二进制数最后一位正好==k值==1时(相当于输入 1 1 特殊情况)
            if int(bstr[i]) == k:
                cnt += 1
            break
        cnt += plus
        k -= 1
print(cnt, end='')

在使用python的情况下速度依然达到了159ms,案例也全部AC
思路
  1. 首先想到的是遍历所有可能出现的排列组合情况,但从题目给的数值范围来看肯定会TLE(超时),这种思路不符合实际情况。

  2. 但是思路1的方向是正确的,我们知道傻傻的遍历肯定不行,只有聪明的遍历才能拿到AC,这也是剪枝的思路。

  3. 于是我随便拿一个数12345,观察他的二进制形式 11000000111001,初步可以想到,拿前五位来说,人类一眼就能看出来11000肯定比11100小,可以直接删掉11100—之类的组合。嗯~~~~,思路来了。

  4. 那这么说,我们可以从二进制的高位(即从左到右的顺序)开始,一步步往低位进发。从思路3可以看出,如果原二进制数org_b的某一位是1,排列组合出来的新数new_b的某一位也是1,那情况会比较复杂,需要与原二进制数比较并逐级向低位判断,但如果是new_b的这一位是0呢,不管后面二进制位怎么置1,都不可能比我现在大,所以这时候直接使用排列组合C(k,n)就行,n就是当前二进制位之后的位数。

  5. 从思路4可以看出来,这就是循环判断的过程。如果org_b的一位是1,那么就进行思路4的判断,如果是0,则直接跳过(因为二进制位当中,没有比0更小的数了,锁死了new_b的选择)。

  6. 选择了一个1,就将k值-1,直到最后k值归零,输出cnt即可(也有可能会存在剩余位数小于k值或正好等于k值,cnt+0或+1即可)

结论

至此,流程结束。作为蓝桥杯决赛倒数第二题,有一定的难度和灵活度,但不需要用到dp还是挺友好的

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/950246.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号