新增欧拉第34、35题解法及说明

This commit is contained in:
2026-01-04 22:21:57 +08:00
parent 0be6fed37c
commit 0ea015f3af
5 changed files with 367 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} took {end_time - start_time:.6f} seconds")
return result
return wrapper
# ---------- 1. PRIMES ----------
MAX = 1_000_000
is_p = bytearray(b"\1") * MAX # 1 表示素数0 表示合数(与原来相反,方便理解)
is_p[0] = is_p[1] = 0 # 0和1不是素数
# 优化:使用标准埃拉托斯特尼筛法
for p in range(2, int(MAX**0.5) + 1):
if is_p[p]:
is_p[p * p : MAX : p] = b"\0" * ((MAX - p * p - 1) // p + 1)
# ---------- 2. SCROLLING ----------
def rotations(n: int) -> list[int]:
"""返回 n 的所有旋转(数学移位版,无字符串开销)"""
if n < 10:
return [n]
s = str(n)
k = len(s)
res = []
for i in range(k):
# 使用切片旋转,避免重复计算
rotated = int(s[i:] + s[:i])
res.append(rotated)
return res
# ---------- 3. MAIN ----------
@timer
def main(limit: int = MAX) -> int:
# 预过滤:只要含 0,2,4,5,6,8 就可以跳过除了2和5本身
bad_digits = set("024568")
total = 0
counted = set() # 用于去重,避免重复计数
for p in range(2, limit):
if is_p[p]: # p是素数
# 快速数字过滤2和5是特例
if p != 2 and p != 5:
s = str(p)
if not bad_digits.isdisjoint(s):
continue
# 如果已经统计过,跳过
if p in counted:
continue
# 检查所有旋转
rs = rotations(p)
# 检查所有旋转数是否都是素数
valid = True
for r in rs:
if r >= limit or not is_p[r]:
valid = False
break
if valid:
# 如果是循环素数,统计并标记已计数
total += len(set(rs)) # 使用set避免重复旋转
counted.update(rs)
return total
if __name__ == "__main__":
print(f"循环素数数量: {main()}")