""" The number, 179, is called a circular prime because all rotations of the digits: 179, 791, and 917, are themselves prime. There are thirteen such primes below 100 : 2,3,5,7,11,13,17,31,37,71,73,79, and 97. How many circular primes are there below one million? """ import random import time from itertools import permutations from sqlite3.dbapi2 import Time from typing import Union # 预计算的小素数集合,用于快速排除 _SMALL_PRIMES = frozenset((2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37)) def timer(func): def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) end_time = time.time() print(f"{func.__name__} time: {end_time - start_time:.6f} seconds") return result return wrapper def sieve_best(n: int) -> list[int]: """返回 [2..n) 内所有素数""" if n <= 2: return [] size = (n - 1) // 2 comp = bytearray(size) limit = int(n**0.5) // 2 for i in range(1, limit + 1): if not comp[i]: p = 2 * i + 1 s = (p * p - 1) // 2 comp[s::p] = b"\1" * ((size - s - 1) // p + 1) res = [2, *(2 * i + 1 for i, v in enumerate(comp) if not v)] res.sort() return [i for i in res if i != 1] def is_circular(n: int, primes: list[int]) -> bool: if n < 2: return False if n in [2, 3, 5, 7, 11]: return True digits = str(n) allnum = [digits[i:] + digits[:i] for i in range(len(digits))] for num in allnum: if int(num) not in primes: return False return True def is_probable_prime(n: Union[int, str], k: int = 20) -> bool: """ Miller-Rabin素性检测算法 参数: n: 待检测的整数(支持int或数字字符串) k: 测试次数,误差率约为4^(-k),默认20次(误差率约9e-13) 返回: bool: 如果n很可能是素数返回True,否则返回False """ # 支持字符串输入 if isinstance(n, str): n = int(n) # 基本检查 if n < 2: return False if n in _SMALL_PRIMES: return True # 检查小素数的倍数 for p in _SMALL_PRIMES: if n % p == 0: return False # 特殊情况:偶数(已排除2) if n % 2 == 0: return False # 将 n-1 写成 2^s * d 的形式 d = n - 1 s = 0 while d % 2 == 0: d //= 2 s += 1 # 边界:如果 n-1 可以直接作为基数,避免随机数生成问题 if n < 4: return n in (2, 3) # Miller-Rabin测试 for _ in range(k): # 生成随机基数,范围 [2, n-2] a = random.randrange(2, n - 1) # 计算 x = a^d mod n x = pow(a, d, n) # 如果 x == 1 或 x == n-1,通过本轮测试 if x == 1 or x == n - 1: continue # 重复平方检查 for _ in range(s - 1): x = pow(x, 2, n) if x == n - 1: break else: # 所有平方后都没有得到 n-1,n是合数 return False return True # 优化的确定素数版本(适用于小整数) def is_prime_small(n: int) -> bool: """确定性素数检测,适用于n < 2^64""" if n < 2: return False if n % 2 == 0: return n == 2 if n % 3 == 0: return n == 3 # 检查小素数 for p in _SMALL_PRIMES: if n % p == 0: return n == p # 6k±1 优化检查 i = 5 w = 2 while i * i <= n: if n % i == 0: return False i += w w = 6 - w # 在2和4之间切换:5,7,11,13,17,19... return True # 智能选择函数 def is_prime(n: Union[int, str], k: int = 20) -> bool: """ 智能素数检测:对小整数使用确定性算法,对大整数使用Miller-Rabin 参数: n: 待检测的整数 k: Miller-Rabin测试次数(仅对大整数有效) 返回: bool: 如果是素数返回True """ if isinstance(n, str): n = int(n) # 小整数使用确定性算法 if n < 2**64: return is_prime_small(n) # 大整数使用Miller-Rabin return is_probable_prime(n, k) @timer def main_quick(max: int) -> None: res = set() for i in range(2, max): if is_prime(i): if i in res: continue else: s = str(i) allnums = [s[i:] + s[:i] for i in range(len(s))] flag = 0 for j in allnums: num = int("".join(j)) if is_prime(num): flag += 1 if flag == len(allnums): res.update(allnums) print(len(res)) @timer def main(n: int) -> None: primes = sieve_best(n) circular_primes = [p for p in primes if is_circular(p, primes)] print(len(circular_primes)) if __name__ == "__main__": num = 1000000 main(num) main_quick(num)