88 lines
2.6 KiB
Python
88 lines
2.6 KiB
Python
"""
|
||
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()
|