Let f(n) be the number of sequences of length n that do not have “13” in them, and g(n) be the number of sequences of length n that have “13” in them.
Then f(n) = 10^n - g(n) (in mathematical notation), since the number of possible sequences ( 10^n ) minus those that contain "13".
Base cases:
f(0) = 1 g(0) = 0 f(1) = 10 g(1) = 0
When searching for sequences with “13,” the sequence may have “13” at the beginning. This will take into account the 10^(n-2) possible sequences with "13" in them. He may also have “13” in second position, again considering the 10^(n-2) possible sequences. But if there is a “13” in the third position, and we assumed that there would also be 10^(n-2) possible sequences, we could have those that already had a “13” in the first position twice. Therefore, we must subtract them. Instead, we count 10^(n-4) times f(2) (because these are exactly combinations in the first two positions in which there is no “13”).
eg. for g (5):
g(5) = 10^(n-2) + 10^(n-2) + f(2)*10^(n-4) + f(3)*10^(n-5)
We can rewrite this to look the same everywhere:
g(5) = f(0)*10^(n-2) + f(1)*10^(n-3) + f(2)*10^(n-4) + f(3)*10^(n-5)
Or just the sum f(i)*10^(n-(i+2)) with i from 0 to n-2 .
In Python:
from functools import lru_cache @lru_cache(maxsize=1024) def f(n): return 10**n - g(n) @lru_cache(maxsize=1024) def g(n): return sum(f(i)*10**(n-(i+2)) for i in range(n-1))
lru_cache is optional, but is often a good idea when working with recursion.
>>> [f(n) for n in range(10)] [1, 10, 99, 980, 9701, 96030, 950599, 9409960, 93149001, 922080050]
The results are instant and work for very large numbers .