50题解决中,已有简单解法,在尝试更快的版本。
This commit is contained in:
87
solutions/0050.ConsecutivePrimeSum/euler_50.py
Normal file
87
solutions/0050.ConsecutivePrimeSum/euler_50.py
Normal file
@@ -0,0 +1,87 @@
|
||||
"""
|
||||
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()
|
||||
Reference in New Issue
Block a user