Files
SolutionEuler/solutions/0050.ConsecutivePrimeSum/euler_50.py

88 lines
2.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
The prime 41, can be written as the sum of six consecutive primes:
41 = 2 + 3 + 5 + 7 + 11 + 13
This is the longest sum of consecutive primes that adds to a prime below one-hundred.
The longest sum of consecutive primes below one-thousand that adds to a prime, contains 21 terms,
and is equal to 953.
Which prime, below one-million, can be written as the sum of the most consecutive primes?
"""
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
elapsed_time = end_time - start_time
print(f"{func.__name__} time: {elapsed_time:.6f} seconds")
return result
return wrapper
def primes_list(limit: int = 10**6) -> list[int]:
if limit < 2:
return []
is_prime = bytearray(b"\x01") * limit
is_prime[0:2] = b"\x00\x00" # 更简洁的写法同时置0和1
# 埃氏筛,使用切片赋值加速
# int(limit**0.5) 等价于 isqrt(limit)Python 3.8+ 可用 math.isqrt
for i in range(2, int(limit**0.5) + 1):
if is_prime[i]:
start = i * i
# 计算切片长度:从 start 到 limit步长 i 的元素个数
count = (limit - start + i - 1) // i # 等效于 ceil((limit-start)/i)
if count > 0:
is_prime[start:limit:i] = b"\x00" * count
return [i for i in range(limit) if is_prime[i]]
def max_primes_sum(limit: int = 10**6) -> tuple:
primes = primes_list(limit)
prime_set = set(primes)
# 计算从2开始连续加素数最多能加多少个不超过limit
max_possible_len = 0
temp_sum = 0
for p in primes:
temp_sum += p
if temp_sum >= limit:
break
max_possible_len += 1
# 从最长可能长度往下枚举
for length in range(max_possible_len, 0, -1):
# 滑动窗口计算连续length个素数的和
window_sum = sum(primes[:length])
if window_sum >= limit:
continue
# 滑动窗口遍历所有起始位置
for start in range(len(primes) - length):
if window_sum in prime_set:
return window_sum, length
# 滑动:减去头部,加上尾部
window_sum += primes[start + length] - primes[start]
if window_sum >= limit:
break
return 0, 0
@timer
def main():
limit = int(input("limit:"))
max_sum, max_length = max_primes_sum(limit)
print(f"max primt: {max_sum}, max_length: {max_length}")
if __name__ == "__main__":
main()