《算法零基础100讲》(第12讲) 因子和
零、写在前面
这是《算法零基础100讲》 专栏打卡学习的第十二天了。
在刷题的过程中,总结自己遇到的坑点,写出 「 解题报告 」 供他人学习,也是一种自我学习的方式。这就是经典的帮助他人的同时,成就自己。目前, 「 万人千题 」 社区 每天都会有五六篇高质量的 「 解题报告 」 被我 「 加精 」。如果觉得自己有能力的,也可以来发布你的 「 解题报告 」。千万级流量,你我共同拥有。
一、概念定义
如何求一个数
的因子和呢?
考虑数
,令
的因子和为
,对
进行素数分解后的,假设最小素数为
,素因子
的个数为
,那么
容易得知,当 的因子中 的个数为 时,因子之和为 。更加一般地,当 的因子中 的个数为 的时候,因子之和为 ,所以 的所有因子之和就可以表示成:
可以通过相同方法递归计算。最后可以表示成一系列等比数列和的乘积。如下:
二、题目描述
给定一个 个整数的数组 ,元素的范围小于等于 的正整数,请你返回该数组中恰有四个因数的这些整数的各因数之和。
三、算法详解
根据因子数的定义,有四个因子数的数,有两种情况:
1)两个素数的乘积,即
;
2)某个素数的三次幂,即
;
所以可以先对 10^5 内的所有的数进行素数筛选。然后遍历数组,对于每个数
,进行
范围内的素数进行试除:
如果能够分解成两个素数的乘积,则继续根据 因子和 的公式,计算因子和。具体的,如果
,则因子和为
如果能够分解一个素数的三次幂,则计算公式为:
四、源码剖析
#define maxn 100001
#define ll long long
bool f[maxn];
int primes[maxn];
void ethPrime(){
int i;
ll j;
f[0] = f[1] = 1;
primes[0] = 0;
for(i = 2; i < maxn; ++i) {
if(!f[i]) {
primes[++primes[0]] = i;
for(j = (ll)i * i; j < maxn; j += i) {
f[j] = 1;
}
}
}
}
bool isPrime(int x) {
return !f[x];
}
int sumFourDivisors(int* nums, int numsSize){
int i, j, p, q;
int ans = 0;
ethPrime(); // (1)
for(i = 0; i < numsSize; ++i) { // (2)
for(j = 1; j <= primes[0]; ++j) { // (3)
p = primes[j];
if(nums[i] % p == 0) {
q = nums[i] / p;
if( isPrime(q) && p != q) {
ans += (p+1)*(q+1); // (4)
}
if( q == (long long)p * p ) {
ans += p*p*p + p*p + p + 1; // (5)
}
break;
}
}
}
return ans;
}
- 基本上数论的题,都离不开 素数筛选;
- 枚举每个数 ;
-
primes[0]
记录了题目范围内的素数个数,枚举范围内的素数; - 当一个数是 的形式,则它 因子和 为 ;
- 当一个数是 的形式,则它的 因子和 为 ;
五、推荐专栏
六、习题练习
- 点赞
- 收藏
- 关注作者
评论(0)