-
-
Notifications
You must be signed in to change notification settings - Fork 50.3k
Expand file tree
/
Copy pathsol1.py
More file actions
94 lines (72 loc) · 2.69 KB
/
sol1.py
File metadata and controls
94 lines (72 loc) · 2.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
"""
Problem 108: https://projecteuler.net/problem=108
Problem Statement:
In the following equation x, y, and n are positive integers.
1/x + 1/y = 1/n
For n = 4 there are exactly three distinct solutions:
1/5 + 1/20 = 1/4
1/6 + 1/12 = 1/4
1/8 + 1/8 = 1/4
What is the least value of n for which the number of distinct solutions
exceeds one-thousand?
Solution:
For a given n, the number of distinct solutions is (d(n * n) // 2) + 1,
where d is the divisor counting function. Find an arbitrary n with more
than 1000 solutions, so n is an upper bound for the answer. Find
prime factorizations for all i < n, allowing easy computation of d(i * i)
for i <= n. Then try all i to find the smallest.
"""
def find_primes(limit: int) -> list[int]:
"""
Returns a list of all primes less than or equal to 'limit'
>>> find_primes(19)
[2, 3, 5, 7, 11, 13, 17, 19]
"""
sieve = [True] * (limit + 1)
for i in range(2, limit + 1):
for j in range(2 * i, limit + 1, i):
sieve[j] = False
return [i for i in range(2, limit + 1) if sieve[i]]
def find_prime_factorizations(limit: int) -> list[dict[int, int]]:
"""
Returns a list of prime factorizations of 2...n, with prime
factorization represented as a dictionary of (prime, exponent) pairs
>>> find_prime_factorizations(7)
[{}, {}, {2: 1}, {3: 1}, {2: 2}, {5: 1}, {2: 1, 3: 1}, {7: 1}]
"""
primes = find_primes(limit)
prime_factorizations: list[dict[int, int]] = [{} for _ in range(limit + 1)]
for p in primes:
for j in range(p, limit + 1, p):
j_factorization = prime_factorizations[j]
x = j
while x % p == 0:
x //= p
j_factorization[p] = j_factorization.get(p, 0) + 1
return prime_factorizations
def num_divisors_of_square(prime_factorization: dict[int, int]) -> int:
"""
Returns the number of divisors of n * n, where n is the
number represented by the input prime factorization
>>> num_divisors_of_square({2: 2, 3: 2}) # n = 36
25
"""
num_divisors = 1
for _, e in prime_factorization.items():
num_divisors *= 2 * e + 1
return num_divisors
def solution(target: int = 1000) -> int:
"""
Returns the smallest n with more than 'target' solutions
>>> solution()
180180
"""
upper_bound = 210 ** ((int((2 * target - 1) ** 0.25) + 1) // 2)
prime_factorizations = find_prime_factorizations(upper_bound)
for i in range(2, upper_bound + 1):
num_solutions = (num_divisors_of_square(prime_factorizations[i]) // 2) + 1
if num_solutions > target:
return i
return -1
if __name__ == "__main__":
print(f"{solution() = }")