一、试除法求质数
1、思路
想要判断一个数n是否是质数,最暴力的方法是从1到n-1遍历,如果有一个数能将n整除,就代表n不是质数
我们可以发现,对于n来说,n的最大的一个因数不会超过根号n,即i*i<=n。
所以我们只用枚举到根号n即可
时间复杂度为O(根号n)
2、代码模板:
#include<iostream> using namespace std; bool su(int x) { if(x<2) return 0; for(int i=2;i<=x/i;i++) { if(x%i==0) return 0; } return 1; } int n; int main() { scanf("%d",&n); while(n--) { int x; scanf("%d",&x); if(su(x)) printf("Yes\n"); else printf("No\n"); } return 0; }
二、埃氏筛法
1、思路
当我们从小到大遍历到每个数时,直接把这个数的倍数全部筛掉。
时间复杂度为O(nlogn)
对于判断一个数字是否是素数有点慢
这个算法用来判断从1到n的所有质数。
对于朴素法埃氏筛来说,还有个优化版,因为每个合数都能分解为质数的积,所有我们只用把质数的倍数筛掉,这样可以避免一个数被重复筛掉
如6会被2和3重复筛掉。
优化版埃氏筛时间复杂度为O(nloglogn)
比朴素版快了3倍
2、代码模板:
朴素法埃氏筛:
#include<iostream> using namespace std; const int N=1e6+10; int n,cnt;//cnt用来存下标 int primes[N];//记录所有质数 bool st[N];//0代表是质数。1代表不是质数 int main() { scanf("%d",&n); for(int i=2;i<=n;i++) { if(!st[i])//如果i是质数 primes[cnt++]=i; for(int j=1;j<=n/i;j++) st[i*j]=1;//倍数标记为合数 } printf("%d",cnt); return 0; }
优化版埃氏筛法
#include<iostream> using namespace std; const int N=1e6+10; int n,cnt;//cnt用来存下标 int primes[N];//记录所有质数 bool st[N];//0代表是质数。1代表不是质数 int main() { scanf("%d",&n); for(int i=2;i<=n;i++) { if(!st[i])//如果i是质数 { primes[cnt++]=i; for(int j=1;j<=n/i;j++) st[i*j]=1;//倍数标记为合数 } } printf("%d",cnt); return 0; }
三、线性筛(最快)
1、思路
每一个合数都会被它的最小质因子筛掉。
速度比优化版的埃氏筛快1倍
2、代码模板:
#include<iostream> using namespace std; const int N=1e6+10; int n,cnt;//cnt用来存下标 int primes[N];//记录所有质数 bool st[N];//0代表是质数。1代表不是质数 int main() { scanf("%d",&n); for(int i=2;i<=n;i++) { if(!st[i]) primes[cnt++]=i; for(int j=0;primes[j]<=n/i;j++) { st[primes[j]*i]=1;//将质数的倍数标记为合数 if(i%primes[j]==0)//当primes[j]是i的最小质因子时跳出 break; } } printf("%d",cnt); return 0; }
四、6倍原理
1、思路
除了2和3,每一个质数,都在6的倍数的左右,
时间复杂度和时除法差不多,比试除法快一点点
2、代码模板:
#include<iostream> using namespace std; bool su(int x) { if(x<2) return 0; if(x==2||x==3)//2,3特判 return 1; if(x%6!=1&&x%6!=5)//当x不为6左右两边的数时就不是质数 return 0; for(int i=5;i<=x/i;i+=6) { if(x%i==0||x%(i+2)==0) return 0; } return 1; } int n; int main() { scanf("%d",&n); while(n--) { int x; scanf("%d",&x); if(su(x)) printf("Yes\n"); else printf("No\n"); } return 0; }
五、分解质因数
1、原理
和试除法差不多,每次遇到质因数就一直除直到不能整除再换下一个
时间复杂度为O(根号n)
n最多有一个大于根号n的质因子。
2、代码模板:
#include<iostream> using namespace std; int n; int main() { scanf("%d",&n); while(n--) { int x; scanf("%d",&x); for(int i=2;i<=x/i;i++) { int sum=0; if(x%i==0) { while(x%i==0) { x/=i; sum++; } printf("%d %d\n",i,sum); } } if(x>1) printf("%d 1\n",x); printf("\n"); } return 0; }