195 lines
6.0 KiB
Python
195 lines
6.0 KiB
Python
"""
|
||
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 itertools
|
||
import time
|
||
from collections import Counter
|
||
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 replace_digit(
|
||
number: str | int,
|
||
target_digit: str | int,
|
||
replace_count: int = 3,
|
||
replacement_digit: str | int = "0123456789",
|
||
return_positions: bool = False,
|
||
) -> list[str] | list[tuple]:
|
||
"""
|
||
使用单个替换数字,替换指定数量的目标数字
|
||
|
||
参数:
|
||
number: 输入的数字(字符串或整数)
|
||
target_digit: 要被替换的目标数字(如 '1')
|
||
replace_count: 要替换的数量(必须 <= 目标数字出现的次数)
|
||
replacement_digit: 用于替换的数字(单个字符)
|
||
return_positions: 是否同时返回被替换的位置信息
|
||
|
||
返回:
|
||
如果return_positions为False,返回替换后的数字列表
|
||
如果return_positions为True,返回[(替换后的数字, 被替换的位置), ...]
|
||
"""
|
||
# 转换为字符串处理
|
||
num_str = str(number)
|
||
target = str(target_digit)
|
||
replacement = str(replacement_digit)
|
||
|
||
# 找出所有目标数字的位置
|
||
target_positions = [i for i, digit in enumerate(num_str) if digit == target]
|
||
|
||
# 检查是否有足够的目标数字
|
||
if len(target_positions) < replace_count:
|
||
return [
|
||
f"错误:目标数字 '{target}' 只出现了 {len(target_positions)} 次,少于要替换的数量 {replace_count}"
|
||
]
|
||
|
||
results = []
|
||
|
||
# 遍历所有可能的要替换的位置组合
|
||
for positions in itertools.combinations(target_positions, replace_count):
|
||
# 创建新数字的列表
|
||
num_list = list(num_str)
|
||
|
||
# 替换指定位置
|
||
for pos in positions:
|
||
num_list[pos] = replacement
|
||
|
||
new_number = "".join(num_list)
|
||
|
||
if return_positions:
|
||
results.append((new_number, positions))
|
||
else:
|
||
results.append(new_number)
|
||
|
||
return results
|
||
|
||
|
||
def replace_muldigits(
|
||
number: str | int,
|
||
target_digit: str | int,
|
||
replace_count: int = 3,
|
||
replacement_digits: str | list[str] = "0123456789",
|
||
return_positions: bool = False,
|
||
) -> list:
|
||
"""
|
||
使用多个替换数字,每个数字单独进行替换
|
||
|
||
参数:
|
||
number: 输入的数字
|
||
target_digit: 目标数字
|
||
replace_count: 要替换的数量
|
||
replacement_digits: 多个替换数字(字符串或列表)
|
||
return_positions: 是否返回位置信息
|
||
|
||
返回:
|
||
字典,键为替换数字,值为对应的结果列表
|
||
"""
|
||
# 转换替换数字为列表
|
||
if isinstance(replacement_digits, str):
|
||
replacement_list = list(replacement_digits)
|
||
else:
|
||
replacement_list = replacement_digits
|
||
|
||
results = {}
|
||
|
||
for rep_digit in replacement_list:
|
||
results[rep_digit] = replace_digit(
|
||
number, target_digit, replace_count, rep_digit, return_positions
|
||
)
|
||
|
||
results = list(results.values())
|
||
res = [[] for _ in range(len(results[0]))]
|
||
for r in results:
|
||
for i, val in enumerate(r):
|
||
if val[0] != "0":
|
||
res[i].append(int(val))
|
||
|
||
return [sorted(list(set(val))) for val in res]
|
||
|
||
|
||
def primes_list(limit: int = 10**8) -> list[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]
|
||
|
||
|
||
def have_n_primes(primes: list[int], target: list[int]) -> int:
|
||
count = 0
|
||
for n in target:
|
||
if n in primes:
|
||
count += 1
|
||
return count
|
||
|
||
|
||
@timer
|
||
def solve() -> list[int]:
|
||
primes = primes_list()
|
||
for p in primes:
|
||
if p < 1000:
|
||
continue
|
||
digits = [int(d) for d in str(p)]
|
||
digit_counts = Counter(digits)
|
||
if max(digit_counts.values()) < 3:
|
||
continue
|
||
digs = [k for k, v in digit_counts.items() if v >= 3 and k in [0, 1, 2]]
|
||
for dig in digs:
|
||
testList = replace_muldigits(p, dig)
|
||
for xList in testList:
|
||
if have_n_primes(primes, xList) == 8:
|
||
return [x for x in xList if x in primes]
|
||
|
||
return []
|
||
|
||
|
||
if __name__ == "__main__":
|
||
result = solve()
|
||
print(result)
|