文章目录
质数:
- 质数:一个正整数不能被除了1和它本身的任何一个自然数整除的数称为质数(prime)
求质数
试除:
- 根据质数的定义,我们可以发现:若 ( 1 < k < n ) ( 1< k<n) (1<k<n)都不能能整除 n n n,则 n n n为质数,进一步思考:如果 k ∣ n k\mid n k∣n则定会有一个 k 1 × k = n k_1\times k=n k1×k=n且 k 1 ≤ n k_1\leq \sqrt n k1≤n.
- 所以对于任意正整数,只需要枚举2~ n \sqrt n n的所有数判断是否为 n n n的约数就能判断 n n n是否为质数.
筛法:
- 当我们求1~n的所有质数时上述方法的时间复杂度就为 O ( n × n ) O(n\times \sqrt n ) O(n×n).
- 但使用埃氏筛,线性筛可以将复杂度优化到 O ( n × log log n ) O(n\times \log\log n) O(n×loglogn)和 O ( n ) O(n) O(n)
埃氏筛
- 1.能被两个或多个数相乘得到的数一定不是质数.
- 2.任何一个合数都能被若干个质数相乘得到.(算数唯一分解定理)
反证法:
假设存在一个合数n不是由若干个质数相乘得出,n存在一个最小的合数m,
因为m为合数,则定有 a × b = m a\times b=m a×b=m
若a,b均为质数,则与假设相矛盾,假设不成立,
若a,b中有一个为质数,则会存在一个更小的合数 m 1 , m_1, m1,与假设相矛盾,假设不成立
- 3.假设x为一个质数,则小于 x 2 x^2 x2的合数会被小于x的另一个质数y所更新(x会乘到y,同理y会乘到x)
- 根据以上三点,我们可以得到埃拉托斯特尼筛法,简称埃氏筛
for(int i = 2; i <= n; i ++){
//注意这个从2开始,1特殊处理(筛2~n的质数)
if( t[i] == 0 ) prime[ ++tot ] = i;//0代表从未被标记,即i是质数
for(int j = i * i; j <= n; j += i){
//从i^2开始(上述第3条)
t[j] = 1;//标记程到的合数
}
}
线性筛
1.与埃氏筛原理一样,用质数标记合数
2.不同点:线性筛确认了更新一个合数的唯一方式,即用这个数的最小质数去标记,所以线性筛的时间复杂度为 O ( n ) O(n) O(n)
3.实现方法:
for(int i = 2; i <= n; i ++){
if(t[i] == 0){
t[i] = i;//更新一个质数的最小质数当然是它本身
ptime[++tot] = i;
}
for(int i = 1; i <= tot; i ++){
//枚举每一个已标记的质数,去更新
if(prime[i] > t[i] || prime[j] > n / i) break;//线性筛的核心
//如果prime[i]>t[i],则不满足对i*prime[j]的最小更新,自己举个例子(感性理解一下)
t[i * prime[i]]