solutions of problem 21 and problem 20

This commit is contained in:
2025-12-21 17:45:44 +08:00
parent a1f849985e
commit 1747152a4d
4 changed files with 305 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
"""
Let d(n) be defined as the sum of proper divisors of n (numbers less than n which divide evenly into n).
If d(a) = b and d(b) = a, where a ≠ b, then a and b are an amicable pair and each of a and b are called amicable numbers.
For example, the proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 44, 55, and 110; therefore d(220) = 284.
The proper divisors of 284 are 1, 2, 4, 71, and 142; so d(284) = 220.
Evaluate the sum of all the amicable numbers under 10000.
"""
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:.8f} seconds")
return result
return wrapper
def sieve_primes(limit):
"""埃拉托斯特尼筛法生成质数列表"""
is_prime = [True] * (limit + 1)
is_prime[0:2] = [False, False]
primes = []
for i in range(2, limit + 1):
if is_prime[i]:
primes.append(i)
for j in range(i * i, limit + 1, i):
is_prime[j] = False
return primes
def prime_factors_with_sieve(n, primes):
"""使用预计算的质数列表进行分解"""
factors = {}
temp = n
for p in primes:
if p * p > temp:
break
while temp % p == 0:
factors[p] = factors.get(p, 0) + 1
temp //= p
if temp > 1:
factors[temp] = factors.get(temp, 0) + 1
return factors
def get_divisors_optimized(n):
"""优化版本:预计算质数加速分解"""
if n < 2:
return [1] if n == 1 else []
# 计算需要的质数范围
limit = int(n**0.5) + 1
primes = sieve_primes(limit)
# 质因数分解
factors = prime_factors_with_sieve(n, primes)
# 生成除数
divisors = [1]
for p, exp in factors.items():
powers = [p**e for e in range(exp + 1)]
divisors = [a * b for a in divisors for b in powers]
return sorted(divisors)
def sum_of_divisors(n):
"""计算一个数的所有真因子之和"""
return sum(get_divisors_optimized(n)) - n
def find_amicable_numbers(limit):
"""查找小于给定上限的全部亲和数对"""
amicable_pairs = set()
for a in range(2, limit):
b = sum_of_divisors(a)
if a != b and sum_of_divisors(b) == a:
amicable_pairs.add((min(a, b), max(a, b)))
return amicable_pairs
@timer
def sum_of_amicable_numbers(limit):
"""计算小于给定上限的全部亲和数之和"""
return sum(a + b for a, b in find_amicable_numbers(limit))
if __name__ == "__main__":
print(sum_of_amicable_numbers(10000))