From 3358e97dd411f08c2bbef269e8bb46b593eba3a3 Mon Sep 17 00:00:00 2001 From: Sidney Zhang Date: Tue, 17 Mar 2026 17:18:41 +0800 Subject: [PATCH] =?UTF-8?q?50=E9=A2=98=E6=9A=82=E7=AE=97=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E5=90=A7=E2=80=A6=E2=80=A6=E4=BD=86=E9=80=9F=E5=BA=A6=E4=BE=9D?= =?UTF-8?q?=E7=84=B6=E4=B8=8D=E6=98=AF=E5=BE=88=E6=BB=A1=E6=84=8F=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../euler_50_better.py | 65 ++++++++++++++----- 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/solutions/0050.ConsecutivePrimeSum/euler_50_better.py b/solutions/0050.ConsecutivePrimeSum/euler_50_better.py index 8ca1b29..04fd82e 100644 --- a/solutions/0050.ConsecutivePrimeSum/euler_50_better.py +++ b/solutions/0050.ConsecutivePrimeSum/euler_50_better.py @@ -14,12 +14,14 @@ from math import isqrt, log from bitarray import bitarray +_prime_cache = set() + def timer(func): def wrapper(*args, **kwargs): - start_time = time.time() + start_time = time.perf_counter() result = func(*args, **kwargs) - end_time = time.time() + end_time = time.perf_counter() elapsed_time = end_time - start_time print(f"{func.__name__} time: {elapsed_time:.6f} seconds") return result @@ -27,9 +29,16 @@ def timer(func): return wrapper -def primes_list(limit: int = 10**6) -> list[int]: - if limit < 2: +def n_primes(n: int = 4000) -> list[int]: + if n < 0: + raise ValueError("n must be a positive integer") + if n == 0: return [] + if n == 1: + return [2] + + # 使用Dusart方法估计上限 + limit = int(n * (log(n) + log(log(n)) - 0.5)) # 初始化全1(假设都是素数),0和1置为0 is_prime = bitarray(limit + 1) @@ -45,7 +54,38 @@ def primes_list(limit: int = 10**6) -> list[int]: is_prime[i * i : limit + 1 : i] = False # 提取结果 - return [i for i, val in enumerate(is_prime) if val] + result = [] + for i, val in enumerate(is_prime): + if val: + result.append(i) + if len(result) >= n: + break + + return result + + +def is_prime(num: int) -> bool: + if num in _prime_cache: + return True + if num < 2: + return False + if num in (2, 3): + _prime_cache.add(num) + return True + if num % 2 == 0 or num % 3 == 0: + return False + + # 检查6k±1形式的因子 + i = 5 + w = 2 + while i * i <= num: + if num % i == 0: + return False + i += w + w = 6 - w # 在2和4之间切换,实现6k±1的检查 + + _prime_cache.add(num) + return True def get_bound(limit: int = 10**6) -> int: @@ -54,7 +94,7 @@ def get_bound(limit: int = 10**6) -> int: """ def f(t: float) -> float: - return t**2 * (2 * log(t) - 1) - 4 * limit + return t**2 * (2 * log(t) - 1) - 2 * limit def fp(t: float) -> float: return 4 * t * log(t) @@ -66,9 +106,9 @@ def get_bound(limit: int = 10**6) -> int: def max_primes_sum_best(limit: int = 10**6) -> tuple[int, int] | None: + # === 1. 确定搜索范围 === bound = get_bound(limit) - primes = primes_list(bound) - prime_set = set(primes) + primes = n_primes(bound) # === 2. 构建前缀和数组 === # prefix[i] 表示前 i 个素数的和(primes[0] 到 primes[i-1]) @@ -104,22 +144,15 @@ def max_primes_sum_best(limit: int = 10**6) -> tuple[int, int] | None: # 计算连续素数之和:primes[left] 到 primes[right-1] consecutive_sum = prefix[right] - prefix[left] - # 修正:如果 sum 已经超过 limit,left 继续增大 sum 会减小,所以不应 break - # 但我们可以加一个判断:如果 prefix[right] - prefix[left] > limit,且 left 还在增大... - # 实际上 left 增大,sum 减小,所以一旦 sum < limit,后续都 < limit - # 简单处理:直接检查,不 break(或者可以预先判断,但为清晰起见省略) - if consecutive_sum >= limit: continue # 跳过,但继续尝试更大的 left(sum 会变小) - if consecutive_sum in prime_set: + if is_prime(consecutive_sum): length = right - left if length > best_length: best_length = length best_prime = consecutive_sum - # 更新剪枝边界:后续需要找比当前更长的,所以 max_left 可以缩小 - # 但 Python 的 range 已经确定,我们只需依赖外层的 right <= best_length 判断 return best_prime, best_length