Skip to content

Commit b1a382b

Browse files
committed
Add Euler project problem 124 solution.
1 parent 0c8cf8e commit b1a382b

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-0
lines changed

project_euler/problem_124/__init__.py

Whitespace-only changes.

project_euler/problem_124/sol1.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
"""
2+
Project Euler Problem 124: https://projecteuler.net/problem=124
3+
4+
Ordered Radicals
5+
6+
"""
7+
8+
from numpy import sqrt
9+
10+
11+
def generate_primes(n: int) -> list[int]:
12+
"""
13+
Calculates the list of primes up to and including n.
14+
15+
>>> generate_primes(6)
16+
[2, 3, 5]
17+
"""
18+
19+
primes = [True] * (n + 1)
20+
primes[0] = primes[1] = False
21+
for i in range(2, int(sqrt(n + 1)) + 1):
22+
if primes[i]:
23+
j = i * i
24+
while j <= n:
25+
primes[j] = False
26+
j += i
27+
primes_list = []
28+
for i in range(2, len(primes)):
29+
if primes[i]:
30+
primes_list += [i]
31+
return primes_list
32+
33+
34+
def generate_n(factors: list[int], n_max: int, n: int, res: set[int]):
35+
"""
36+
Generates all numbers n that can be constructed out of 'factors', with any
37+
multiplicity, but that do no exceed 'n_max'.
38+
39+
>>> generate_n([2], 10, 1, set())
40+
"""
41+
42+
if len(factors) == 0:
43+
return
44+
fac = factors[0]
45+
factors_new = factors[1:]
46+
while n <= n_max:
47+
generate_n(factors_new, n_max, n, res)
48+
res.add(n)
49+
n *= fac
50+
return
51+
52+
53+
def generate_rads(
54+
factors_all: list[int], n_max: int, n: int, res: dict, factors_prev: list[int]
55+
):
56+
"""
57+
Generates all rads and associated factors, e.g., rad = factor_1 * ... * factor_k.
58+
Output is stored in 'res' dict argument.
59+
60+
>>> generate_rads([2], 10, 1, {}, [])
61+
"""
62+
63+
for i in range(len(factors_all)):
64+
f = factors_all[i]
65+
n_new = n * f
66+
if n_new > n_max:
67+
return
68+
# factors_new = factors_prev + [f]
69+
factors_new = [*factors_prev, f]
70+
res[n_new] = factors_new
71+
generate_rads(factors_all[(i + 1) :], n_max, n_new, res, factors_new)
72+
return
73+
74+
75+
def solution(n_max: int = 100000, k: int = 10000) -> int:
76+
"""
77+
Loops over sorted 'rads' and generates all numbers 'n' for rad.
78+
Keeps track of total number of n, and when k falls inside some rad,
79+
it sorts all 'n' for it and picks up associated n.
80+
81+
>>> solution(10, 6)
82+
9
83+
>>> solution(10, 9)
84+
7
85+
"""
86+
87+
if k == 1:
88+
return 1
89+
90+
primes = generate_primes(n_max)
91+
tot = 1
92+
rads_d: dict[int, list[int]] = {}
93+
factor_prev: list[int] = []
94+
generate_rads(primes, n_max, 1, rads_d, factor_prev)
95+
rads = sorted(rads_d)
96+
97+
for r in rads:
98+
facts = rads_d[r]
99+
res: set[int] = set()
100+
generate_n(facts, n_max, r, res)
101+
res_len = len(res)
102+
if tot + res_len >= k:
103+
return sorted(res)[k - tot - 1]
104+
tot += res_len
105+
return -1
106+
107+
108+
if __name__ == "__main__":
109+
print(f"{solution() = }")

0 commit comments

Comments
 (0)