mirror of
https://github.com/TheAlgorithms/Python.git
synced 2024-12-18 01:00:15 +00:00
60f9895685
* Fixes: #3163 - Add new solution for problem 234 * Apply review suggestions
120 lines
3.2 KiB
Python
120 lines
3.2 KiB
Python
"""
|
|
https://projecteuler.net/problem=234
|
|
|
|
For an integer n ≥ 4, we define the lower prime square root of n, denoted by
|
|
lps(n), as the largest prime ≤ √n and the upper prime square root of n, ups(n),
|
|
as the smallest prime ≥ √n.
|
|
|
|
So, for example, lps(4) = 2 = ups(4), lps(1000) = 31, ups(1000) = 37. Let us
|
|
call an integer n ≥ 4 semidivisible, if one of lps(n) and ups(n) divides n,
|
|
but not both.
|
|
|
|
The sum of the semidivisible numbers not exceeding 15 is 30, the numbers are 8,
|
|
10 and 12. 15 is not semidivisible because it is a multiple of both lps(15) = 3
|
|
and ups(15) = 5. As a further example, the sum of the 92 semidivisible numbers
|
|
up to 1000 is 34825.
|
|
|
|
What is the sum of all semidivisible numbers not exceeding 999966663333 ?
|
|
"""
|
|
|
|
import math
|
|
|
|
|
|
def prime_sieve(n: int) -> list:
|
|
"""
|
|
Sieve of Erotosthenes
|
|
Function to return all the prime numbers up to a certain number
|
|
https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
|
|
>>> prime_sieve(3)
|
|
[2]
|
|
>>> prime_sieve(50)
|
|
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
|
|
"""
|
|
is_prime = [True] * n
|
|
is_prime[0] = False
|
|
is_prime[1] = False
|
|
is_prime[2] = True
|
|
|
|
for i in range(3, int(n ** 0.5 + 1), 2):
|
|
index = i * 2
|
|
while index < n:
|
|
is_prime[index] = False
|
|
index = index + i
|
|
|
|
primes = [2]
|
|
|
|
for i in range(3, n, 2):
|
|
if is_prime[i]:
|
|
primes.append(i)
|
|
|
|
return primes
|
|
|
|
|
|
def solution(limit: int = 999_966_663_333) -> int:
|
|
"""
|
|
Computes the solution to the problem up to the specified limit
|
|
>>> solution(1000)
|
|
34825
|
|
|
|
>>> solution(10_000)
|
|
1134942
|
|
|
|
>>> solution(100_000)
|
|
36393008
|
|
"""
|
|
primes_upper_bound = math.floor(math.sqrt(limit)) + 100
|
|
primes = prime_sieve(primes_upper_bound)
|
|
|
|
matches_sum = 0
|
|
prime_index = 0
|
|
last_prime = primes[prime_index]
|
|
|
|
while (last_prime ** 2) <= limit:
|
|
next_prime = primes[prime_index + 1]
|
|
|
|
lower_bound = last_prime ** 2
|
|
upper_bound = next_prime ** 2
|
|
|
|
# Get numbers divisible by lps(current)
|
|
current = lower_bound + last_prime
|
|
while upper_bound > current <= limit:
|
|
matches_sum += current
|
|
current += last_prime
|
|
|
|
# Reset the upper_bound
|
|
while (upper_bound - next_prime) > limit:
|
|
upper_bound -= next_prime
|
|
|
|
# Add the numbers divisible by ups(current)
|
|
current = upper_bound - next_prime
|
|
while current > lower_bound:
|
|
matches_sum += current
|
|
current -= next_prime
|
|
|
|
# Remove the numbers divisible by both ups and lps
|
|
current = 0
|
|
while upper_bound > current <= limit:
|
|
if current <= lower_bound:
|
|
# Increment the current number
|
|
current += last_prime * next_prime
|
|
continue
|
|
|
|
if current > limit:
|
|
break
|
|
|
|
# Remove twice since it was added by both ups and lps
|
|
matches_sum -= current * 2
|
|
|
|
# Increment the current number
|
|
current += last_prime * next_prime
|
|
|
|
# Setup for next pair
|
|
last_prime = next_prime
|
|
prime_index += 1
|
|
|
|
return matches_sum
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print(solution())
|