小素数,大智慧
- 定义
- 判断方法
- 方法1
- 方法2
- 方法3
- 方法4
- 方法5
- 方法6
- 方法7
定义
素数(质数):在大于 1 的自然数中,只有 1 和该数本身两个因数的数 素数(质数):在大于1的自然数中,只有1和该数本身两个因数的数 素数(质数):在大于1的自然数中,只有1和该数本身两个因数的数
判断方法
方法1
时间复杂度 O ( n ) 时间复杂度O(n) 时间复杂度O(n)
定义法 定义法 定义法
bool isPrime(int n){if(n < 2) return false;for(int i = 2; i < n; i++) if(n % i == 0) reutrn false;return true;
}
方法2
时间复杂度 O ( n 2 ) 时间复杂度O(\sqrt{\frac{n}{2}}) 时间复杂度O(2n)
性质:对于合数 a ,一定存在素数 p 1 ≤ a ≤ p 2 使得 p 1 性质:对于合数a,一定存在素数p_1≤\sqrt{a}≤p_2使得p_1 性质:对于合数a,一定存在素数p1≤a≤p2使得p1 ∣ | ∣ a , p 2 a,p_2 a,p2 ∣ | ∣ a (定性理解) a(定性理解) a(定性理解)
定量证明 定量证明 定量证明
原理:检验 [ 1 , n ] 区间里的数是否有约数,检验区间从 [ 1 , n ] 缩小到 [ 1 , n ] 原理:检验[1,\sqrt{n}]区间里的数是否有约数,检验区间从[1,n]缩小到[1,\sqrt{n}] 原理:检验[1,n]区间里的数是否有约数,检验区间从[1,n]缩小到[1,n]
bool isPrime(int n){if(n < 2) return false;for(int i = 2; i < sqrt(n); i++) if(n % i == 0) reutrn false;return true;
}
方法3
在方法 2 的基础上,只筛奇数 在方法2的基础上,只筛奇数 在方法2的基础上,只筛奇数
因为除 2 以外的偶数都是合数,直接跳过,只关心奇数即可 因为除2以外的偶数都是合数,直接跳过,只关心奇数即可 因为除2以外的偶数都是合数,直接跳过,只关心奇数即可
bool isPrime(int n){if(n < 2) return false;for(int i = 2; i < sqrt(n); i++) if(n % 2 == 0 || n % i == 0) reutrn false;return true;
}
方法4
原理:所有大于 3 的素数都可以表示为 6 n ± 1 的形式 原理:所有大于3的素数都可以表示为6n±1的形式 原理:所有大于3的素数都可以表示为6n±1的形式
证明: n ∈ N , n 可以用 6 n − 1 ( 6 n − 1 < = > 6 n + 5 ) 、 6 n 、 6 n + 1 、 6 n + 2 、 6 n + 3 、 6 n + 4 表示 证明:n∈N,n可以用6n-1(6n-1<=>6n+5)、6n、6n+1、6n+2、6n+3、6n+4表示 证明:n∈N,n可以用6n−1(6n−1<=>6n+5)、6n、6n+1、6n+2、6n+3、6n+4表示
其中, 6 n 是 6 的倍数,不是素数 其中,6n是6的倍数,不是素数 其中,6n是6的倍数,不是素数
6 n + 2 是偶数,只有 n = 0 时, 6 n + 2 = 2 才是素数 6n+2是偶数,只有n=0时,6n+2=2才是素数 6n+2是偶数,只有n=0时,6n+2=2才是素数
6 n + 3 是 3 的倍数,只有 n = 0 时, 6 n + 3 = 3 才是是质数 6n+3是3的倍数,只有n=0时,6n+3=3才是是质数 6n+3是3的倍数,只有n=0时,6n+3=3才是是质数
6 n + 4 是偶数,且大于 2 ,不是质数 6n+4是偶数,且大于2,不是质数 6n+4是偶数,且大于2,不是质数
所以,当 n > 0 时, 6 n ± 1 是质数 所以,当n>0时,6n±1是质数 所以,当n>0时,6n±1是质数
证毕 . 证毕. 证毕.
bool isPrime(int n){if(n < 2) return false;if(n % 6 != 1 && n % 6 != 5) return false;for(int i = 5; i <= sqrt(n); i += 6) if(n % i == 0) return false;return true;
}
方法5
埃拉托斯特尼筛法
Eratosthenes筛选
#include<bits/stdc++.h>
using namespace std;
int main(){int n, p = 0;//p:素数的个数 cin >> n;bool is_prime[n + 5];//标记是否为素数 int prime[n + 5];//prime[p]:第p位素数 for(int i = 0; i <= n; i++) is_prime[i] = true;is_prime[0] = is_prime[1] = false;for(int i = 2; i <= n; i++){if(is_prime[i] != 0){prime[p++] = i;for(int j = i + i; j <= n; j += i) is_prime[j] = false;}}return 0;
}
优化 1 优化1 优化1
只筛奇数 只筛奇数 只筛奇数
把 2 的倍数筛掉,直接让 i 从 3 开始循环每次加 2 把2的倍数筛掉,直接让i从3开始循环每次加2 把2的倍数筛掉,直接让i从3开始循环每次加2
这样做内存需求减半,操作大约也减半 这样做内存需求减半,操作大约也减半 这样做内存需求减半,操作大约也减半
#include<bits/stdc++.h>
using namespace std;
int main(){int n, p = 1;//p:素数的个数 cin >> n;bool is_prime[n + 5];//标记是否为素数 int prime[n + 5];//prime[p]:第p位素数 for(int i = 0; i <= n; i++) is_prime[i] = true;is_prime[0] = is_prime[1] = false;prime[1] = 2;for(int i = 3; i <= n; i += 2){if(i % 2 != 0 && is_prime[i] != 0){prime[p++] = i;for(int j = i + i; j <= n; j += i) is_prime[j] = false;}}return 0;
}
优化 2 优化2 优化2
假设存在 x < i 2 ,不妨设 x = a × b ( a < b ) 假设存在x<i^2,不妨设x=a×b(a<b) 假设存在x<i2,不妨设x=a×b(a<b)
如果 a , b > i ,那么 a × b > i 2 ,与假设 x < i 2 矛盾 如果a,b>i,那么a×b>i^2,与假设x<i^2矛盾 如果a,b>i,那么a×b>i2,与假设x<i2矛盾
因此,有 a ≤ i 因此,有a≤i 因此,有a≤i
这意味着当我们循环 f o r 到 i 之前,就早已经将这个数 x 筛过 这意味着当我们循环for到i之前,就早已经将这个数x筛过 这意味着当我们循环for到i之前,就早已经将这个数x筛过
所以我们优化从 i 2 开始标记 所以我们优化从i^2开始标记 所以我们优化从i2开始标记
#include<bits/stdc++.h>
using namespace std;
int main(){int n, p = 1;//p:素数的个数 cin >> n;bool is_prime[n + 5];//标记是否为素数 int prime[n + 5];//prime[p]:第p位素数 for(int i = 0; i <= n; i++) is_prime[i] = true;is_prime[0] = is_prime[1] = false;prime[1] = 2;for(int i = 3; i <= n; i += 2){if(i % 2 != 0 && is_prime[i] != 0){prime[p++] = i;for(int j = i * i; j <= n; j += i) is_prime[j] = false;}}return 0;
}
优化 3 优化3 优化3
vector
#include<bits/stdc++.h>
using namespace std;
int main(){int n, p = 1;//p:素数的个数 cin >> n;vector<int> prime;//prime[p]:第p位素数vector<bool> is_prime(n + 5, true);//标记是否为素数 is_prime[0] = is_prime[1] = false;prime.push_back(2);for(int i = 3; i <= n; i += 2){if(i % 2 != 0 && is_prime[i] != 0){prime.push_back(i);for(int j = i * i; j <= n; j += i) is_prime[j] = false;}}return 0;
}
优化 4 优化4 优化4
bitset
⚠ ⚠ ⚠ b i t s e t 的大小得是确定的 bitset的大小得是确定的 bitset的大小得是确定的
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1000000;
int main(){int n, p = 1;//p:素数的个数 cin >> n;vector<int> prime;//prime[p]:第p位素数bitset<MAXN + 5> is_prime; //标记是否为素数is_prime.set();//都标记为true is_prime[0] = is_prime[1] = false;prime.push_back(2);for(int i = 3; i <= n; i += 2){if(i % 2 != 0 && is_prime[i] != 0){prime.push_back(i);for(int j = i * i; j <= n; j += i) is_prime[j] = false;}}return 0;
}
方法6
分块筛选
方法7
线性筛法
Euler 筛法
欧拉筛法
参考
https://blog.csdn.net/way_back/article/details/122760006
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;int main(){vector<int> prime(10000, 1);for(int i=2; i<100; i++){if(prime[i]){for(int j=i; i*j<10000; j++)prime[i*j] = 0;}}ifstream in("prime.txt");for(int k; in>>k && k>1 && k<10000; )cout << k << " is " << (prime[k] ? "":"not ") << "a prime." << endl;return 0;
}
bool isPrime4(int n) {bool yes = false;int num[SIZE] = { 0 };for (int i = 2; i < SIZE; i++) {if (!num[i]) {for (int j = i + i; j < SIZE; j += i) {num[j] = 1;}}}if (!num[n]) {yes = true;}return yes;
}
bool isPrime5(int n) {bool yes = false;int num[SIZE] = { 0 };if (n == 2) {yes = true;}else {for (int i = 0; i < SIZE; i++) {if (!num[i]) {for (int j = (2 * i + 3) * (2 * i + 3); j < (2 * SIZE + 3); j += 2 * (2 * i + 3)) {num[(j - 3) / 2] = 1;}}}}if ((n - 3) % 2 == 0) {if (!num[(n - 3) / 2]) {yes = true;}}return yes;
}