解题思路:对于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分
2 人评分
C语言程序设计教程(第三版)课后习题10.3 (C语言代码)浏览:711 |
奖学金 (C++代码)浏览:2056 |
C语言程序设计教程(第三版)课后习题6.3 (C语言代码)浏览:511 |
矩阵乘法 (C++代码)浏览:1662 |
兰顿蚂蚁 (C++代码)浏览:1225 |
C语言程序设计教程(第三版)课后习题1.5 (C语言代码)浏览:672 |
C语言程序设计教程(第三版)课后习题6.3 (C语言代码)浏览:1001 |
简单的a+b (C语言代码)浏览:560 |
WU-C语言程序设计教程(第三版)课后习题12.1 (C++代码)浏览:1025 |
幸运数 (C++代码)浏览:1309 |