81 lines
2.2 KiB
Python
81 lines
2.2 KiB
Python
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()}")
|