diff --git a/project_euler/problem_113/__init__.py b/project_euler/problem_113/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/project_euler/problem_113/sol1.py b/project_euler/problem_113/sol1.py new file mode 100644 index 000000000..951d9b49c --- /dev/null +++ b/project_euler/problem_113/sol1.py @@ -0,0 +1,75 @@ +""" +Project Euler Problem 113: https://projecteuler.net/problem=113 + +Working from left-to-right if no digit is exceeded by the digit to its left it is +called an increasing number; for example, 134468. + +Similarly if no digit is exceeded by the digit to its right it is called a decreasing +number; for example, 66420. + +We shall call a positive integer that is neither increasing nor decreasing a +"bouncy" number; for example, 155349. + +As n increases, the proportion of bouncy numbers below n increases such that there +are only 12951 numbers below one-million that are not bouncy and only 277032 +non-bouncy numbers below 10^10. + +How many numbers below a googol (10^100) are not bouncy? +""" + + +def choose(n: int, r: int) -> int: + """ + Calculate the binomial coefficient c(n,r) using the multiplicative formula. + >>> choose(4,2) + 6 + >>> choose(5,3) + 10 + >>> choose(20,6) + 38760 + """ + ret = 1.0 + for i in range(1, r + 1): + ret *= (n + 1 - i) / i + return round(ret) + + +def non_bouncy_exact(n: int) -> int: + """ + Calculate the number of non-bouncy numbers with at most n digits. + >>> non_bouncy_exact(1) + 9 + >>> non_bouncy_exact(6) + 7998 + >>> non_bouncy_exact(10) + 136126 + """ + return choose(8 + n, n) + choose(9 + n, n) - 10 + + +def non_bouncy_upto(n: int) -> int: + """ + Calculate the number of non-bouncy numbers with at most n digits. + >>> non_bouncy_upto(1) + 9 + >>> non_bouncy_upto(6) + 12951 + >>> non_bouncy_upto(10) + 277032 + """ + return sum(non_bouncy_exact(i) for i in range(1, n + 1)) + + +def solution(num_digits: int = 100) -> int: + """ + Caclulate the number of non-bouncy numbers less than a googol. + >>> solution(6) + 12951 + >>> solution(10) + 277032 + """ + return non_bouncy_upto(num_digits) + + +if __name__ == "__main__": + print(f"{solution() = }")