✨ feat(solutions):新增欧拉项目第25-27题解决方案
📝 docs(solutions):添加Binet公式、循环节和质数生成多项式的数学原理文档
This commit is contained in:
135
solutions/0026.ReciprocalCycles/euler_26.py
Normal file
135
solutions/0026.ReciprocalCycles/euler_26.py
Normal file
@@ -0,0 +1,135 @@
|
||||
"""
|
||||
A unit fraction contains 1in the numerator.
|
||||
The decimal representation of the unit fractions with denominators 2 to 10 are given:
|
||||
|
||||
1/2 = 0.5
|
||||
1/3 = 0.(3)
|
||||
1/4 = 0.25
|
||||
1/5 = 0.2
|
||||
1/6 = 0.1(6)
|
||||
1/7 = 0.(142857)
|
||||
1/8 = 0.125
|
||||
1/9 = 0.(1)
|
||||
1/10 = 0.1
|
||||
|
||||
Where 0.1(6) means 0.166666..., and has a 1-digit recurring cycle.
|
||||
It can be seen that 1/7 has a 6-digit recurring cycle.
|
||||
|
||||
Find the value of d < 1000 for which 1/d contains the longest recurring cycle in its decimal fraction part.
|
||||
"""
|
||||
|
||||
import random
|
||||
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
|
||||
|
||||
|
||||
def repeating_cycle_fermat(d: int) -> int:
|
||||
# 移除因子2和5
|
||||
while d % 2 == 0:
|
||||
d //= 2
|
||||
while d % 5 == 0:
|
||||
d //= 5
|
||||
|
||||
if d == 1:
|
||||
return 0
|
||||
|
||||
# 费马小定理:对于与10互质的d,10^(φ(d)) ≡ 1 mod d
|
||||
# 循环节长度一定是φ(d)的约数
|
||||
|
||||
# 计算欧拉函数φ(d)
|
||||
phi = d
|
||||
n = d
|
||||
# 质因数分解求φ(d)
|
||||
p = 2
|
||||
while p * p <= n:
|
||||
if n % p == 0:
|
||||
phi -= phi // p
|
||||
while n % p == 0:
|
||||
n //= p
|
||||
p += 1 if p == 2 else 2 # 从2开始,然后检查奇数
|
||||
|
||||
if n > 1:
|
||||
phi -= phi // n
|
||||
|
||||
# 现在找φ的最小约数k,使得10^k ≡ 1 mod d
|
||||
min_cycle = phi
|
||||
for k in range(1, int(phi**0.5) + 1):
|
||||
if phi % k == 0:
|
||||
if pow(10, k, d) == 1:
|
||||
return k
|
||||
other = phi // k
|
||||
if pow(10, other, d) == 1 and other < min_cycle:
|
||||
min_cycle = other
|
||||
|
||||
return min_cycle
|
||||
|
||||
|
||||
@timer
|
||||
def main_searchall(n: int) -> None:
|
||||
max_cycle = 0
|
||||
max_d = 0
|
||||
for d in range(1, n):
|
||||
cycle = repeating_cycle_fermat(d)
|
||||
if cycle > max_cycle:
|
||||
max_cycle = cycle
|
||||
max_d = d
|
||||
|
||||
print(f"{max_d} have {max_cycle} digits in its decimal fraction part.")
|
||||
|
||||
|
||||
def is_probable_prime(n: int, trials: int = 20) -> bool:
|
||||
"""Miller-Rabin素性测试(快速判断是否为质数)"""
|
||||
if n < 2:
|
||||
return False
|
||||
if n in (2, 3):
|
||||
return True
|
||||
if n % 2 == 0:
|
||||
return False
|
||||
|
||||
# 将 n-1 写成 d * 2^s 的形式
|
||||
d = n - 1
|
||||
s = 0
|
||||
while d % 2 == 0:
|
||||
d //= 2
|
||||
s += 1
|
||||
|
||||
# 测试
|
||||
for _ in range(trials):
|
||||
a = random.randrange(2, n - 1)
|
||||
x = pow(a, d, n)
|
||||
if x == 1 or x == n - 1:
|
||||
continue
|
||||
for _ in range(s - 1):
|
||||
x = pow(x, 2, n)
|
||||
if x == n - 1:
|
||||
break
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@timer
|
||||
def main_by_prime(n: int) -> None:
|
||||
for d in range(n, 0, -1):
|
||||
max_cycle = d - 1
|
||||
max_d = d
|
||||
cycle = repeating_cycle_fermat(d)
|
||||
if max_cycle == cycle:
|
||||
print(f"{max_d} have {max_cycle} digits in its decimal fraction part.")
|
||||
return None
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
n = 10000
|
||||
main_searchall(n)
|
||||
main_by_prime(n)
|
||||
Reference in New Issue
Block a user