解题思路:对于10%的案例都要求10**10次方暴力法肯定是不行滴.要学会差分答案,最后把答案一个个累加起来.先计算传入的数所在的二进制位数(最大)然后就是后面的数从里面随便选k个数都成立(要满足后面的二进制位数大于或等于k哦) 现在答案是不是还差最高位,那就选中最高位,然后k-1,计算剩余数m=n(传入的数)-最高位的数,现在的问题是不是又回去了,得到一个新的数,拆分,拆分,最后把答案加起来就可以了

注意事项:
先注意递归阶乘要小心0,将0的条件分出来。最后要注意剩余的二进制位数和需要的k位的大小关系就可以啦 分情况想啦 国赛的题目都是思维非常严谨的 多做就可以啦 大家加油哦
参考代码:

#两个递归函数求阶乘 数学选举的思想 就是从多少个数选几个数,不排列问题啦

from math import *
def func1(m,n):#m为位数 n为个数
   if m==0:
       return 1
   if n>1:
       return m*func1(m-1,n-1)
   else:
       return m
def func2(n):
   if n>1:
       return n*func2(n-1)
   else:
       return n
# 传入数据
data=list(map(int,input().split(' ')))
n,k=data[0],data[1]
count=0#累加答案
while 1:
   w = int(log(n, 2))# 总位数-1
   # 第一种情况就是总位数小于传入的k 直接退出
   if w+1<k:
       print(count)
       break
   # 第二种就是总位数等于传入的k 分两种情况
   # 情况1-剩余值n小于所有位的和-不够退出
   elif w+1==k and n<sum(list(2**x for x in range(k))):
       print(count)
       break
   # 情况2-剩余值n大于等于所有位的和-只有一种情况加1
   elif w+1==k and n>=sum(list(2**x for x in range(k))):
       count+=1
       print(count)
       break
   # 第三种就是总位数大于传入的k
   else:
       add1=func1(w,k)#参数分别为位数和变化后的k
       add2=func2(k)
       add=add1//add2 #一部分答案
       count+=add
       max=2**w#最高位数
       n-=max # 还剩余多少
       k-=1 #获取了最高位 k要减1
       # 一旦k为1 就直接从剩余的位数里面选1个-数学问题
       if k==1:
           w = int(log(n, 2))
           add1=func1(w+1, k) #w+1应该要包含所有的数 要包含最高位
           add2=func2(k)
           add = add1//add2
           count += add
           print(count)
           break
       # 一旦剩余值n 为0就是恰好满足二进制里面的一位记mm 就要分情况了
       if n<1:
           # 情况1 k的值刚好为1
           if k==1:
               count+=1
               print(count)
               break
           # 情况2 k不为1 还要位置-满足不了 直接退出
           else:
               print(count)
               break



点赞(0)
 

0.0分

2 人评分

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

评论列表 共有 0 条评论

暂无评论