Amicable numbers
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.
题目:
d(n) 定义为 n 的所有真因子(小于 n 且能整除 n 的整数)之和。
如果 d(a) = b 并且 d(b) = a, 且 a ≠ b, 那么 a 和 b 就是一对相亲数(amicable pair),并且 a 和 b 都叫做亲和数(amicable number)。
例如 220 的真因子是 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 和 110; 因此 d(220) = 284. 284 的真因子是 1, 2, 4, 71 和 142; 所以 d(284) = 220.
计算 10000 以下所有亲和数之和。
这个题理解就是,一个数的除了它本身的所有因子相加等于另一个数,另一个数的除了它本身的所有因子相加等于之前那个数,那这两个数就是亲和数
那么题意理解了,现在的问题就是如何去求每个数的它本身的因子,最暴力的解法,每个数都去余,取余为0就是他的因子;那这个时间复杂度得多高,O(nlogn),但是题目的数比较小10000,那程序运行时间也不会很长,这个方法可以用;这个方法就博主就不写代码了;我主要说效率更高的方式;
以欧拉12题的的思想来看,一个数的因子个数等于他的质因子的幂次加一相乘得来的;那么举个例:
18的因子有:1,2,3,6,9, 18
转化为质数的幂次来表示:
那么18的真因子和为
那么可以得公式:
pi就是第i个质因子,ai表示他有多少幂次
公式展开就是,在用等比数列求和:
那么如果两个数互质,说明他们之间的都没有相同的质因子,那他们相乘,就可以得到:
qi和pi是一定是互质的,如果他们俩不互质,那么n和m就不互质,所以最终可以得到上面的公式;
现在两个数不互质,他们之间只相差一个最小质因子的倍数,那么
F(m)和F(n)除了第一项,后面项都是相同的那么就可以用F(A)来表示F(B)
展开
最终得到
那么由上面两个性质和之前线性筛的思想就可以完成这个题目,下面是代码实现:
#include <stdio.h> #include <math.h> #define MAX_N 10000 int prime[MAX_N + 5];//判断是否是质数 int cnt[MAX_N + 5];//最小质因子个数 int f[MAX_N + 5];//因子和 int main() { for (int i = 2; i < MAX_N; i++) { if (!prime[i]) { prime[++prime[0]] = i; cnt[i] = 1;//因为他为质数所以他的最小质因子就是它本身只有一次 f[i] = 1 + i;//他的因子和就是1+它本身 } for (int j = 1; i * prime[j] < MAX_N; j++) { prime[i * prime[j]] = 1; if (i % prime[j] == 0) { f[i * prime[j]] = f[i] / (1 - pow(prime[j], (cnt[i] + 1))) * (1 - pow(prime[j], (cnt[i] + 2)));//根据这两个数只相差最小质因子的倍数的公式得来 cnt[i * prime[j]] = cnt[i] + 1;//他的最小质因子多了一次就是 break; } else { f[i * prime[j]] = f[i] * f[prime[j]];//两个数互质的公式 cnt[i * prime[j]] = 1;//他的最小质因子就是prime[j] } } } int ans = 0; for (int i = 2; i < MAX_N; i++) { int ind = f[i] - i;//求得他真因子和,因为上面求出来是包括它本身的因子和 if (ind == i) continue;//题目要求a不等于b就是,不能是它本身 if (i != f[ind] - ind) continue;//如果i的真因子和的真因子和的不等于i那就继续循环 ans += i; } printf("%d\n", ans); return 0; }
最终答案:31626