素数
素数
素数,又叫质数,定义是除了1和它本身以外不再有其他的因数
根据定义,可以用以下程序来判断一个数是否为素数
bool prime(int x) {//判断x是否为质数,时间复杂度为O(n) if(x <= 1) return false; for(int i = 2; i < x; i ++) if(x % i == 0) return false; return true; }
接下来要加速了哦
bool prime2(int x){ //判断是否为质数,时间复杂度为O(sqrt(n)) if(x <= 1) return false; for(int i = 2; i <= sqrt(x + 0.5); i ++) //0.5是防止根号的精度误差 if(x % i == 0) return false; return true; //另一种写法,可避免根号的精度误差 if(x <= 1) return false; for(int i = 2; i * i <= x; i++) if(x % i == 0) return false; return true; }
虽然已经挺快的了,但是如果 n 比较大的话就不好玩了
so... 接下来我们要讲一种更快的算法——埃拉托斯特尼筛法(咦~,好长),那就简称埃氏筛法吧
原理:如果找到一个质数,那么这个质数的倍数都不是质数
void init() { //时间复杂度O(nloglogn) 我也不知道怎么算出来的 2333 for(int i = 2; i < N; i++) prime[i] = true; for(int i = 2; i * i < N; i++) if(prime[i]) for(int j = i * i; j < N; j += i) //因为之前的都判断过了,所以从i*i开始就可以了 prime[j] = false; } int main() { scanf("%d", &N); init(); }
线性筛法(欧拉筛法)
保证每个合数只会被它的最小质因数筛去,因此每个数只会被标记一次,所以时间复杂度是O(n)
void prime() { for(int i = 2; i < n; i++) { if(!check[i]) prime[tot++] = i; for(int j = 0; j < tot; ++j) { if(i * prime[j] > n) break; check[i * prime[j]] = 1; if(i % prime[j] == 0) break; } } }
基于埃式筛法的原理,我们可以用它干很多事,比如:
#include<cstdio> #include<vector> using namespace std; const int N = 100000 + 5; vector<int> prime_factor[N]; void init() { for(int i = 2; i < N; i ++) if(prime_factor[i].size() == 0) //如果i是质数 for(int j = i; j < N; j += i) prime_factor[j].push_back(i); } int main() { init(); }
#include<cstdio> #include<vector> using namespace std; const int N = 100000 + 5; vector<int> factor[N]; void init() { for(int i = 2; i < N; i ++) for(int j = i; j < N; j += i) factor[j].push_back(i); } int main() { init(); }
#include<cstdio> #include<vector> using namespace std; const int N = 100000 + 5; vector<int> prime_factor[N]; void init() { int temp; for(int i = 2; i < N; i ++) if(prime_factor[i].size() == 0) for(int j = i; j < N; j += i){ temp = j; while(temp % i == 0){ prime_factor[j].push_back(i); temp /= i; } } } int main() { init(); }
推荐博客(专门讲素数的哦):https://www.cnblogs.com/grubbyskyer/p/3852421.html