Project-Euler-012积性函数性质

012题:

题意:

​ 三角形数数列是通过逐个加上自然数来生成的。例如,第7个三角形数是 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28。三角形数数列的前十项分别是:

​ 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, …

​ 让我们列举出前七个三角形数的所有约数:
1:1
3:1,3
6: 1,2,3,6
​ 10: 1,2,5,10
​ 15: 1,3,5,15
​ 21: 1,3,7,21
​ 28: 1,2,4,7,14,28

​ 我们可以看出,28是第一个拥有超过5个约数的三角形数。

​ 第一个拥有超过500个约数的三角形数是多少?

思路:

​ 任何一个数都可以写成一个或多个素数的乘积,我们设为n = p1^n1 * p2 ^ n2 *…

​ 因此,一个数的因子个数,等同于(n1 + 1) * (n2 + 1) *…

​ 为什么呢?我们可以想一下,对于素因子p1,我们有n1 + 1种选择,分别是:不选,选一个,选两个…直到选n1个,同理p2有n2+1种选择,所以种类数就是(n1 + 1) * (n2 + 1) *…

​ 因此,我们只需要计算一个数有多少种素因子,每种素因子的个数,就可以通过算式直接求得一个数的因子数,求法有两种:

​ ——一种是预处理全部素数,然后每次遍历整除直到该数为1,时间复杂度是O(n),其中n为满足条件的数

​ ——另一种方式是创建记忆化数组数组,存储每个数的最小素因子。再利用:如果a,b互质,那么num(a ✖️ b) = num (a) ✖️ num(b) ,又因为三角形数都是n / 2 ✖️ (n - 1)或n / 2 ✖️ (n + 1)(n >= 2且n为偶数),所以我们只预处理sqrt(n)项即可(注:num(a)代表数字a的因子数),时间复杂度为O(sqrt(n))

代码:

#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#define ll int64_t
#define d int32_t
#define f double
#define r return
#define mem(a) memset(a, 0, sizeof(a));
#define N 40000

d book[N + 5];      //存储每个数的最小素因子
d prime[N + 5];     //存储2~40000全部素数
d number[N + 5];	//存储前40000数的因子数

//利用线性筛框架初始化
void init() {
    mem(book);
    mem(prime);
    for (d i = 2; i <= N; i++) {
        if (!book[i]) {
            prime[++prime[0]] = i;
            book[i] = i;
        }
        for (d j = 1; j <= prime[0] && prime[j] * i <= N; j++) {
            book[prime[j] * i] = prime[j];
            if (i % prime[j] == 0) break;
        }
    }
    r;
}

//用于求S(n)
ll mul (ll n) {
    r (n + 1) * n / 2;
}

//求n的因子数
d num(ll n) {
    if (n == 1) r 1;
    d res = 1;
    d t = book[n];
    while(n % t == 0) {
        res++;
        n /= t;
    }
    r res * num(n);
}

//利用当a,b互质,num(a * b) = num(a) * num(b)求a*b的因子数
void work () {
    for (ll i = 1; i <= N; i++) {
        number[i] = num(i);
    }
    for (ll i = 2; i <= N; i += 2) {
        d p1 = number[i / 2] * number[i - 1];
        d p2 = number[i / 2] * number[i + 1];
        if (p1 > 500) {
            printf("%" PRId64"\n", i / 2 * (i - 1));
            r;
        } else if(p2 > 500) {
            printf("%" PRId64"\n", i / 2 * (i + 1));
            r;
        }
    }
    r;
}

d main () {
    init();
    work();
    r 0;
}

答案是:76576500

转载请注明出处!!!

如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值