29
29
"""
30
30
from __future__ import annotations
31
31
32
- import math
33
-
34
32
35
33
def get_pascal_triangle_unique_coefficients (depth : int ) -> set [int ]:
36
34
"""
@@ -61,76 +59,9 @@ def get_pascal_triangle_unique_coefficients(depth: int) -> set[int]:
61
59
return coefficients
62
60
63
61
64
- def get_primes_squared (max_number : int ) -> list [int ]:
65
- """
66
- Calculates all primes between 2 and round(sqrt(max_number)) and returns
67
- them squared up.
68
-
69
- >>> get_primes_squared(2)
70
- []
71
- >>> get_primes_squared(4)
72
- [4]
73
- >>> get_primes_squared(10)
74
- [4, 9]
75
- >>> get_primes_squared(100)
76
- [4, 9, 25, 49]
77
- """
78
- max_prime = math .isqrt (max_number )
79
- non_primes = [False ] * (max_prime + 1 )
80
- primes = []
81
- for num in range (2 , max_prime + 1 ):
82
- if non_primes [num ]:
83
- continue
84
-
85
- for num_counter in range (num ** 2 , max_prime + 1 , num ):
86
- non_primes [num_counter ] = True
87
-
88
- primes .append (num ** 2 )
89
- return primes
90
-
91
-
92
- def get_squared_primes_to_use (
93
- num_to_look : int , squared_primes : list [int ], previous_index : int
94
- ) -> int :
95
- """
96
- Returns an int indicating the last index on which squares of primes
97
- in primes are lower than num_to_look.
98
-
99
- This method supposes that squared_primes is sorted in ascending order and that
100
- each num_to_look is provided in ascending order as well. Under these
101
- assumptions, it needs a previous_index parameter that tells what was
102
- the index returned by the method for the previous num_to_look.
103
-
104
- If all the elements in squared_primes are greater than num_to_look, then the
105
- method returns -1.
106
-
107
- >>> get_squared_primes_to_use(1, [4, 9, 16, 25], 0)
108
- -1
109
- >>> get_squared_primes_to_use(4, [4, 9, 16, 25], 0)
110
- 1
111
- >>> get_squared_primes_to_use(16, [4, 9, 16, 25], 1)
112
- 3
62
+ def get_squarefrees (unique_coefficients : set [int ]) -> set [int ]:
113
63
"""
114
- idx = max (previous_index , 0 )
115
-
116
- while idx < len (squared_primes ) and squared_primes [idx ] <= num_to_look :
117
- idx += 1
118
-
119
- if idx == 0 and squared_primes [idx ] > num_to_look :
120
- return - 1
121
-
122
- if idx == len (squared_primes ) and squared_primes [- 1 ] > num_to_look :
123
- return - 1
124
-
125
- return idx
126
-
127
-
128
- def get_squarefree (
129
- unique_coefficients : set [int ], squared_primes : list [int ]
130
- ) -> set [int ]:
131
- """
132
- Calculates the squarefree numbers inside unique_coefficients given a
133
- list of square of primes.
64
+ Calculates the squarefree numbers inside unique_coefficients.
134
65
135
66
Based on the definition of a non-squarefree number, then any non-squarefree
136
67
n can be decomposed as n = p*p*r, where p is positive prime number and r
@@ -140,27 +71,27 @@ def get_squarefree(
140
71
squarefree as r cannot be negative. On the contrary, if any r exists such
141
72
that n = p*p*r, then the number is non-squarefree.
142
73
143
- >>> get_squarefree ({1}, [] )
144
- set()
145
- >>> get_squarefree ({1, 2}, [] )
146
- set()
147
- >>> get_squarefree ({1, 2, 3, 4, 5, 6, 7, 35, 10, 15, 20, 21}, [4, 9, 25] )
74
+ >>> get_squarefrees ({1})
75
+ {1}
76
+ >>> get_squarefrees ({1, 2})
77
+ {1, 2}
78
+ >>> get_squarefrees ({1, 2, 3, 4, 5, 6, 7, 35, 10, 15, 20, 21})
148
79
{1, 2, 3, 5, 6, 7, 35, 10, 15, 21}
149
80
"""
150
81
151
- if len (squared_primes ) == 0 :
152
- return set ()
153
-
154
82
non_squarefrees = set ()
155
- prime_squared_idx = 0
156
- for num in sorted (unique_coefficients ):
157
- prime_squared_idx = get_squared_primes_to_use (
158
- num , squared_primes , prime_squared_idx
159
- )
160
- if prime_squared_idx == - 1 :
161
- continue
162
- if any (num % prime == 0 for prime in squared_primes [:prime_squared_idx ]):
163
- non_squarefrees .add (num )
83
+ for number in unique_coefficients :
84
+ divisor = 2
85
+ copy_number = number
86
+ while divisor ** 2 <= copy_number :
87
+ multiplicity = 0
88
+ while copy_number % divisor == 0 :
89
+ copy_number //= divisor
90
+ multiplicity += 1
91
+ if multiplicity >= 2 :
92
+ non_squarefrees .add (number )
93
+ break
94
+ divisor += 1
164
95
165
96
return unique_coefficients .difference (non_squarefrees )
166
97
@@ -170,15 +101,14 @@ def solution(n: int = 51) -> int:
170
101
Returns the sum of squarefrees for a given Pascal's Triangle of depth n.
171
102
172
103
>>> solution(1)
173
- 0
104
+ 1
174
105
>>> solution(8)
175
106
105
176
107
>>> solution(9)
177
108
175
178
109
"""
179
110
unique_coefficients = get_pascal_triangle_unique_coefficients (n )
180
- primes = get_primes_squared (max (unique_coefficients ))
181
- squarefrees = get_squarefree (unique_coefficients , primes )
111
+ squarefrees = get_squarefrees (unique_coefficients )
182
112
return sum (squarefrees )
183
113
184
114
0 commit comments