欧拉计划第21题

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

转化为质数的幂次来表示:2^0*3^0,2^1*3^0,2^0*3^1,2^1*3^1,2^0*3^2,2^1*3^2

那么18的真因子和为

F(18) = 2^0*3^0+2^1*3^0+2^0*3^1+2^1*3^1+2^0*3^2+2^1*3^2\\ =(2^0 + 2 ^ 1) * (3 ^ 0 + 3 ^ 1 + 3 ^ 2)

那么可以得公式:

F(n) =\prod_{i}^{n}p_{i}^{ai}

pi就是第i个质因子,ai表示他有多少幂次

公式展开就是,在用等比数列求和:

F(n) = \prod_{i}^{n}(p_{i}^{0}+p_{i}^{1}+....p_{i}^{ai})\\ =\prod_{i}^{n}(1-q_{i}^{ai + 1})/(1-p_{i})

那么如果两个数互质,说明他们之间的都没有相同的质因子,那他们相乘,就可以得到:

F(n) * F(m) = \prod_{i}^{n}q_{i}^{ai} * \prod_{i}^{m}p_{i}^{bi}

qi和pi是一定是互质的,如果他们俩不互质,那么n和m就不互质,所以最终可以得到上面的公式;

现在两个数不互质,他们之间只相差一个最小质因子的倍数,那么

n = p_1^{a_1} * p_2^{a_2} *...p_n^{a_n}\\ m = p_1 * n

F(m) = \prod_{i =1}^{n} p_1^{a1 + 1}\\ F(n) = \prod_{i =1}^{n} p_1^{a1}\\

F(m)和F(n)除了第一项,后面项都是相同的那么就可以用F(A)来表示F(B)

F(B) = F(A) / p_1^{a1}* p_2^{a2}

展开

F(B) = F(A) / ((1 - q_1^{a_1 + 1}) / (1 - q_1)) * ((1-q_1^{a_1 + 2}) / (1 -q_1))

最终得到

F(B) = F(A) * (1-q_q^{a_1 + 2}) / (1-q_q^{a_1 + 1})

那么由上面两个性质和之前线性筛的思想就可以完成这个题目,下面是代码实现:

#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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

初猿°

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值