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()}")