From 780f04e923e625aa29b7b17a089e63badfcef7e3 Mon Sep 17 00:00:00 2001 From: Freddy Pringle Date: Fri, 9 Oct 2020 12:05:18 +0200 Subject: [PATCH 1/2] Added solution for Project Euler problem 113. Fixes: #2695 --- project_euler/problem_113/__init__.py | 0 project_euler/problem_113/sol1.py | 69 +++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 project_euler/problem_113/__init__.py create mode 100644 project_euler/problem_113/sol1.py diff --git a/project_euler/problem_113/__init__.py b/project_euler/problem_113/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/project_euler/problem_113/sol1.py b/project_euler/problem_113/sol1.py new file mode 100644 index 000000000000..a97cf3ca7b1c --- /dev/null +++ b/project_euler/problem_113/sol1.py @@ -0,0 +1,69 @@ +""" +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() -> int: + """ + Caclulate the number of non-bouncy numbers less than a googol. + """ + return non_bouncy_upto(100) + + +if __name__ == "__main__": + print(solution()) From 6845f5777465e3e388bbbfb1ad5375a684b24ec0 Mon Sep 17 00:00:00 2001 From: Freddy Pringle Date: Thu, 15 Oct 2020 09:59:17 +0200 Subject: [PATCH 2/2] Updated formatting and doctests. Reference: #3256 --- project_euler/problem_113/sol1.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/project_euler/problem_113/sol1.py b/project_euler/problem_113/sol1.py index a97cf3ca7b1c..951d9b49c104 100644 --- a/project_euler/problem_113/sol1.py +++ b/project_euler/problem_113/sol1.py @@ -1,4 +1,6 @@ """ +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. @@ -58,12 +60,16 @@ def non_bouncy_upto(n: int) -> int: return sum(non_bouncy_exact(i) for i in range(1, n + 1)) -def solution() -> int: +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(100) + return non_bouncy_upto(num_digits) if __name__ == "__main__": - print(solution()) + print(f"{solution() = }")