素数筛选
“埃式筛法”
具体步骤:引用百度百科
求25以内的所有素数
-
列出2以后的所有序列:
-
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
-
-
标出序列中的第一个素数,也就是2,序列变成:
-
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
-
-
将剩下序列中,划掉2的倍数,序列变成:
-
2 3 5 7 9 11 13 15 17 19 21 23 25
-
-
如果现在这个序列中最大数小于最后一个标出的素数的平方,那么剩下的序列中所有的数都是素数,否则回到第二步。
-
本例中,因为25大于2的平方,我们返回第二步:
-
剩下的序列中第一个素数是3,将主序列中3的倍数划掉,主序列变成:
-
2 3 5 7 11 13 17 19 23 25
-
-
我们得到的素数有:2,3
-
25仍然大于3的平方,所以我们还要返回第二步:
-
现在序列中第一个素数是5,同样将序列中5的倍数划掉,主序列成了:
-
2 3 5 7 11 13 17 19 23
-
-
我们得到的素数有:2,3,5 。
-
因为23小于5的平方,跳出循环.
结论:2到25之间的素数是:2 3 5 7 11 13 17 19 23。
原理当从小到大达到某数a时,如果a没有被前面步骤的数筛去,那么a一定是素数。因为,如果a不是素数,那么a一定有小于a的因子,这样在之前的步骤中a一定会被筛去。所以当枚举到a时,还没有被筛去,那么a一定为素数。
代码如下
const int maxn = 101;
int prime[maxn], pNum = 0;
bool p[maxn] = {0};
void Find_Prime(){
for(int i = 2; i < maxn; i++){
if(p[i] == false){
prime[pNum++] = i;
for(int j = i + i; j < maxn; j += i){
p[j] = true;
}
}
}
}
质因子分解
时间复杂度O(根号n)
由于每个质因子都可能出现不只一次,所以我们用结构体factor用来存放质因子及其个数,
const int maxn = 101;
struct factor{
int x, cnt; //x为质因子数,cnt为其个数
}fac[maxn];
例如给你个180 求 180fac【】数组如下
fac[0].x = 2;
fac[0].cnt = 2;
fac[1].x = 3;
fac[1].cnt = 2;
fac[2].x = 5;
fac[2].cnt = 1;
因为 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)范围内的所有因子p,判断p是否是n的因子。
如果p是n的因子,那么fac【】数组中增加质因子p,并初始化其个数为 0,继续除以p每次令p的个数+1,直到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++;
}
如果p不是n的因子直接跳过。
如果在上述操作后n还>1,说明n有且只有一个大于sqrt(n) 的质因子(可能就是n本身),这时需要把这个因子+入fac数组,并令其个数为1
if(n != 1){
fac[num].x = n;
fac[num++].cnt = 1;
}
时间复杂度O(根号n)。