""" 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))