双十一CF必上1400


私信TA

用户名:dotcpp0602879

访问量:4067

签 名:

放纵是本性,克制是智慧。

等  级
排  名 408
经  验 5036
参赛次数 3
文章发表 22
年  龄 21
在职情况 学生
学  校 江南大学
专  业 软件工程

  自我简介:

蓝桥国一终归与我!

解题思路:对于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 人评分

  评论区

  • «
  • »