Files
SolutionEuler/solutions/0051.PrimeDigitReplace/euler_51_better.py
2026-03-18 18:14:55 +08:00

106 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
By replacing the 1st digit of the 2-digit number *3,
it turns out that six of the nine possible values: 13, 23, 43, 53, 73, and 83, are all prime.
By replacing the 3rd and 4th digits of 56**3 with the same digit,
this 5-digit number is the first example having seven primes among the ten generated numbers,
yielding the family: 56003, 56113, 56333, 56443, 56663, 56773, and 56993.
Consequently 56003, being the first member of this family, is the smallest prime with this property.
Find the smallest prime which,
by replacing part of the number (not necessarily adjacent digits) with the same digit,
is part of an eight prime value family.
-----
*.000*.、*.111*.、*.222*.、*.333*.、*.444*.、*.555*.、*.666*.、*.777*.、*.888*.、*.999*.
数字的形式就是这样,最多十个数,那么,就是要在质数序列上搜索这样的数列:
1. 用欧拉筛生成质数表上限约100万足够
2. 对每个质数p
a. 检查是否有≥3个相同数字且该数字∈{0,1,2}
b. 生成所有C(n,3)种3位替换组合
c. 对每种组合用0-9替换统计质数个数
d. 若得到8个质数返回p首个即为答案
"""
import time
from itertools import combinations
from math import isqrt
from bitarray import bitarray
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
elapsed_time = end_time - start_time
print(f"{func.__name__} time: {elapsed_time:.6f} seconds")
return result
return wrapper
def primes_list(limit: int = 10**8) -> set[int]:
is_prime = bitarray(limit + 1)
is_prime.setall(True)
is_prime[:2] = False # 0和1不是素数
# 只需筛到 sqrt(n)
imax = isqrt(limit) + 1
for i in range(2, imax):
if is_prime[i]:
# 步长i从i*i开始小于i*i的已被更小的素数筛过
is_prime[i * i : limit + 1 : i] = False
return {i for i, isp in enumerate(is_prime) if isp}
@timer
def solve() -> list[int]:
primes = primes_list(10**6)
# 遍历所有可能的模式
for prime in sorted(primes):
if prime < 1000: # 从4位数开始
continue
s = str(prime)
# 检查每个出现3次或以上的数字
for d in set(s):
positions = [i for i, c in enumerate(s) if c == d]
if len(positions) < 3:
continue
# 尝试替换3个位置
for combo in combinations(positions, 3):
if 0 in combo and d == "0":
continue
family = []
for new_d in "0123456789":
new_num_str = "".join(
new_d if i in combo else c for i, c in enumerate(s)
)
new_num = int(new_num_str)
# 确保长度相同且是素数
if len(str(new_num)) == len(s) and new_num in primes:
family.append(new_num)
if len(family) == 8:
return sorted(family)
return [-1]
if __name__ == "__main__":
result = solve()
print(result)