You are given a binary string s representing a number n in its binary form.
You are also given an integer k.
An integer x is called k-reducible if performing the following operation
at mostk times reduces it to 1:
Replace x with the count of set bits in its binary representation.
For example, the binary representation of 6 is "110". Applying the operation once reduces it to 2 (since "110" has two set bits). Applying the operation again to 2 (binary "10") reduces it to 1 (since "10" has one set bit).
Return an integer denoting the number of positive integers less than n
that are k-reducible.
Since the answer may be too large, return it modulo10^9 + 7.
A number is k-reducible if, after at most k operations of replacing it with the count of set bits in its binary representation, it becomes 1. We can use digit DP to count numbers less than n (given as a binary string) that are k-reducible.
MOD =10**9+7from functools import lru_cache
defpopcount(x: int) -> int:
return bin(x).count('1')
defprecompute(maxn: int =1005):
steps = [-1] * maxn
steps[0] =-1 steps[1] =0for i in range(2, maxn):
steps[i] = steps[popcount(i)] +1return steps
classSolution:
defcountKReducibleNumbers(self, s: str, k: int) -> int:
steps = precompute(len(s)*2+5)
n = len(s)
@lru_cache(None)
defdfs(pos: int, cnt: int, tight: int) -> int:
if pos == n:
return int(cnt)
res =0 up = int(s[pos]) if tight else1for d in range(up+1):
res = (res + dfs(pos+1, cnt+d, tight and d==up)) % MOD
return res
ans =0for ones in range(1, n*2+1):
if steps[ones] > k or steps[ones] ==-1:
continue cnt = dfs(0, 0, 1)
if ones ==1:
cnt = (cnt -1+ MOD) % MOD
ans = (ans + cnt) % MOD
return ans
1
// Not practical for Rust due to recursion and memoization limits, see C++/Python.
1
// Not practical for TypeScript due to recursion and memoization limits, see C++/Python.