97 lines
2.6 KiB
Python
97 lines
2.6 KiB
Python
"""
|
|
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))
|