蓝桥20182 知识考量码:递归

https://www.lanqiao.cn/problems/20182/learning/?page=1&first_category_id=1

我们把n,k的解记为solve(n,k),记k的二进制位数为v
把这个问题划分成2个部分,一个是序列中存在第v-1位为1的情况,一个是序列中不存在第v-1位为1的情况。

如果序列中所有元素第v-1位都为0,那么剩下的v-2 ~ 0位都可以无约束地取0或者1
由于题目要求的性质,如果在序列中index = i位置,元素的第x位首次为1,那么在此之后的元素这位就始终为1.
这样,只要考虑v-2~0位的1首次出现的index,即可求出这部分的序列数量:
每个位的1,可能首次出现在index = 0 ~ n - 1, 也可能直接不出现,共 n + 1 种可能。
这部分的序列数量就是:(n + 1) ^ (v - 1)

然后考虑序列中存在第v-1位为1的情况:
这部分可以递归计算,对应的子问题是solve(n, k - (1 << (v-1))),然后第v-1位的1可能出现index = 0 ~ n - 1, 所以要乘n
举个例子:求n = 3, k = 10, 序列中存在大于等于8的元素的序列个数,记这个问题为sub_solve(3,10):
表达式为 sub_solve(3,10) = 3 * solve(3, 2)
solve(3,2) = 4 ^ 1 + 3 * solve(3, 0) = 7
具体的,solve(3,2)中的所有序列为:(0,0,0), (0,0,1), (0,0,2), (0,1,1), (0,2,2), (1,1,1), (2,2,2),其中每个序列可以转化得到3个sub_solve(3,10)中的序列
例如(0,0,0) -> (0,0,8), (0,8,8), (8,8,8)

n, k = map(int, input().split())
MOD = 10 ** 9 + 7

def solve(n, k):
    if k == 0:
        return 1
    v = len(bin(k)) - 3
    return (pow(n + 1, v) + n * solve(n, k - (1 << v))) % MOD

print(solve(n, k))
posted @   凉叶染香  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示