1. 质因子分解
质因子分解是指将一个正整数n写成一个或者多个质数的乘积的形式。
注意:由于1本身并不是素数,因此它没有质因子。 但是对于有些正整数n的题目需要特判1,比如【PAT A1059】Prime Factors这道题就需要特判。
由于每个质因子都可以不止出现一次,因此不妨定义结构体factor
(因子),用来存放质因子及其个数,如下所示:
struct factor{
int x; //x是质因子
int cnt; //cnt是质因子的数量
}fac[10];
这里的fac[]
数组存放的就是给定的正整数n
的所有质因子。例如,对于180来说,fac
数组如下:
考虑到
2
×
3
×
5
×
7
×
11
×
13
×
17
×
19
×
23
×
29
2 \times 3 \times 5 \times 7 \times 11 \times 13 \times 17 \times 19 \times 23 \times 29
2×3×5×7×11×13×17×19×23×29就已经超过了int
范围,因此对一个int
型范围的数来说,fac数组的大小只需要开到10就可以了。
前面提到过,对一个正整数n来说,如果它存在1和本身之外的因子,那么一定是在sqrt(n)
的左右成对出现的。而这里把这个结论用在“质因子”上面,会得到一个强化的结论:
- 对一个正整数
n
来说,如果它存在[2,n]
范围内的质因子,要么这些质因子全部 小于等于sqrt(n)
,要么只存在 一个大于sqrt(n)
的质因子,而其余质因子全部 小于等于sqrt(n)
。
上述的结论为质因子分解提供了一个很好的思路 (三步走) :
-
打印
[1,sqrt(n)]
范围内的素数表 -
枚举
1
~sqrt(n)
范围内的所有质数,判断p是否是n的因子。- 如果
p
是n
的因子,那么fac
数组中添加质因子p,并初始化其个数为0.然后,只要p
还是n
的因子,就让n
不断除以p
,每次操作令p
的个数加1,直到p
不再是n
的因子为止。 - 如果
p
不是n
的因子,就直接跳过。
if(n % prime[i] == 0){ fac[num].x = prime[i]; fac[num].cnt = 0; while(n % prime[i] == 0){ fac[num].cnt++; n /= prime[i]; } num++; }
- 如果
-
如果在上面步骤结束之后,
n
仍然是大于1,说明n
有且仅有一个大于sqrt(n)
的质因子(有可能是n
本身),这时需要把这个质因子加入fac
数组,并令其个数为1.if(n != 1){ fac[num].x = n; fac[num++].cnt = 1; }
至此,fac
数组中存放的就是质因子分解的结果,时间复杂度为
O
(
n
)
O(\sqrt n)
O(n)。
2. 如何求所有因子个数,以及所有因子之和
- 上面的性质需要特别理解!
- 等比公式!
- 因为是质因子,所以它们之间肯定是不相等的,所以一定能保证有那么多的因子数。