数论-质数专题

一.判断质数

  思路:任何一个正整数,他的因数一定是成对出现的,如果一个数 x 有除了1和他本身以外的的其他因数,那么一定是一个因数大于根号x, 另一个小于根号x,所以我们可以根据这个性质,来用试除法进行判断是不是质数。

时间复杂度:O(sqrt(n))

代码:

1 bool is_prime(int x)
2 {
3     if (x < 2) return false;
4     for (int i = 2; i <= x / i; i ++ )
5         if (x % i == 0)
6             return false;
7     return true;
8 }
View Code

二.分解质因数

  思路:任何正整数,都可以表示成 X = P1^a * P2^b * .... * Pn^m, 其中P1 P2 Pn都是质数,也就说在自然界中,质数是原子级别的,任何一个数都可以用质数表示,由此可以推出任何一个正整数最多只有一个大于sqrt(x)的质因数(这是一条性质)

时间复杂度:O(sqrt(n))

代码:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int main(){
 5     int n;
 6     cin >> n;
 7     while(n --){
 8         int a; cin >> a;
 9         //任何一个正整数最多只有一个大于根号a的质因数
10         for(int i = 2;i <= a / i;++i){
11             if(a % i == 0){//i 一定是质数, 因为从2到i-1之间没有一个数是a的因数,a又是i的倍数,所以从2到i-1没有一个数是i的因数,所以i是质数
12                 int s = 0;//i的指数
13                 while(a % i == 0) a = a / i, ++s;//把i除干净
14                 cout << i << " " << s << endl;
15             }
16         }
17         if(a > 1) cout << a << " " << 1 << endl;//因为可能有大于根号a的质因数
18         cout << endl;
19     }
20     return 0;
21 }
View Code

三.筛质数

  思路:有三种方法,分别是朴素筛法,埃式筛法,线性筛法

朴素筛法:

  从2到n枚举每个数 i , 然后把 i 的所有倍数都删掉,如果枚举到某个数p, p没有被删掉,说明从2到p-1之间没有p的因数,所以可以证明p一定是质数,这个算法的缺点是会重复删除,比如, 12,在2的时候删除一次,在3的时候也被删除,由此可见会出现冗余的情况。

时间复杂度:O(nlog(n))

代码:

 1 int cnt;
 2 int flag[N], prim[N];
 3 //朴素筛法 O(nlog(log(n)))
 4 void get_prime1(int n){
 5     for(int i = 2;i <= n;++i){
 6         if(!flag[i])//i 没有删除
 7             prim[++cnt] = i;//prim里存的是所有质数
 8         //用来删除当前所有数的倍数
 9         for(int j = i+i;j <= n;j += i)
10             flag[j] = true;
11     }
12 }
View Code

埃式筛法:

  和朴素筛法不同的就是删除所有质数的倍数 

时间复杂度: O(nlog(log(n)))

代码:

 1 //埃式筛法 O(nlog(log(n)))
 2 void get_prime2(int n){
 3     for(int i = 2;i <= n;++i){
 4         if(!flag[i]){//i 没有删除
 5             prim[++cnt] = i;//prim里存的是所有质数
 6             //用来删除当前所有质数的倍数
 7             for(int j = i+i;j <= n;j += i)
 8                 flag[j] = true;
 9         }
10     }
11 }
View Code

线性筛法:

  每一个和数都有一个最小质因数,所以我们可以用每一个和数的最小质因数来删除这个和数,所以可知不会重复删除,但是代码不太好理解,背熟

时间复杂度:O(n)

代码:

 1 //线性筛法On
 2 void get_prime3(int n){
 3     for(int i = 2;i <= n;++i){
 4         if(!flag[i])prim[++cnt] = i;
 5         for(int j = 1;prim[j] <= n/i;++j){
 6             flag[i*prim[j]] = true;//pj 一定是 i * pj的最小质因数,
 7             if(i % prim[j] == 0)break;
 8         }
 9     }    
10 }
View Code
原文地址:https://www.cnblogs.com/sxq-study/p/12248921.html