素数筛/分解质因数
什么是素数/质数
除了1和本身之外不能被其他数整除的一类数为质数(满足对任意1 < a < n
,n % a != 0
)
,除了素数和1外的正整数都是合数,合数一定有素因子
1既不是素数也不是合数
素数的判断
根据素数的特点,我们要遍历2, 3, 4, …, n - 1,判断是否满足n % a != 0
,这样判断简单直接,但复杂度在O(n),这对于一道题的一小部分来说的确有些大了
我们发现,如果在1 < a < n
中,存在n
的约数k
即n % k == 0
,那么必有n / k
也是n
的约数,且两者必有一个小于sqrt(n)
,这样我们只需要遍历1 < a < sqrt(n)
即可,复杂度降至O(sqrt(n))
bool isPrime(int n)
{
if(n <= 1)
return false;
//注意这里,先转换为浮点型计算,结果再取成整形
int sqr = (int)sqrt(1.0 * n);
for(int i = 2; i <= sqr; ++i)
{
if(n % i == 0)
return false;
}
return true;
}
那么我们要制素数表,即判断1 ~ n
是否是素数,时间复杂度达O(n* sqrt(n)),可以应对**105**以下的数据规模
埃氏筛制素数表O(nloglogn)
算法从小到大枚举所有数,对每一个素数都筛去它的倍数,得到剩下的数便都是素数
例如对于1~20,事先只需确认2是质数即可
删除2的倍数
2 | 3 | 5 | 7 | 9 | 11 | 13 | 15 | 17 | 19 | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
删除3的倍数
2 | 3 | 5 | 7 | 11 | 13 | 17 | 19 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
删除5的倍数
删除7的倍数
…
删除19的倍数
最后,我们得到了剩余的数就是1 ~ 20的素数表
const int maxn = 1e4 + 1; //表长
int prime[maxn], pNum = 0; //prime数组存放所有素数,pNum为素数个数
bool p[maxn]; //如果i为素数,则p[i] = false
void FindPrime()
{
for(int i = 2; i < maxn; ++i)
{
if(p[i] == false)
{
prime[++pNum] = i;
for(int j = 2 * i; j < maxn; j += i)
{
p[j] = true; //筛去所有i的倍数
}
}
}
}
输出10000以内的素数
int main()
{
FindPrime();
for(int i = 1; i <= pNum; ++i)
cout << prime[i];
return 0;
}
应用
这道题看着简单,坑却很深
- 坑1:输出格式,很容易出错,严格按照要求来办
- 坑2:给的范围是在第1e4个素数之内,但是我们制素数表时需要明确最大素数范围;实测第1e4个素数的数量级为1e6,数组开到1e8会爆内存,等于这里1e7是唯一可用的数据规模!
#include <bits/stdc++.h>
using namespace::std;
const int maxn = 1e7; //表长
int prime[maxn], pNum = 0; //prime数组存放所有素数,pNum为素数个数
bool p[maxn] = {0}; //如果i为素数,则p[i] = false
void FindPrime()
{
for(int i = 2; i < maxn; ++i)
{
if(p[i] == false)
{
prime[++pNum] = i;
for(int j = 2 * i; j < maxn; j += i)
{
p[j] = true; //筛去所有i的倍数
}
}
}
}
int main()
{
FindPrime();
int a, b, cnt = 0, ans[10005];
cin >> a >> b;
for(int i = a; i <= b; ++i)
{
ans[++cnt] = prime[i];
}
for(int i = 1; i < cnt; ++i)
{
cout << ans[i];
if(i % 10 == 0)
cout << endl;
else
cout << ' ';
}
cout << ans[cnt];
return 0;
}