判断质数与筛质数

  

  一:判定质数

  要判断一个数是不是质数,只需遍历小于等于它的所有数,如果它能被除了1和本身之外的数整除,那么它就不是质数。

很简单,暴力枚举,代码如下:

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

但是还可以优化,对于一个数$x$,它有一个约数$d$,那么$\frac{x}{d}$也是$x$的约数,所以我们只需要枚举较小的一个就可以了,即$d <\frac{x}{d}$ ,即我们只需枚举到$\sqrt{x}$即可。

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 }

时间复杂度就从原本的$O(n)$降为了$O(\sqrt{n})$。

   

      二:分解质因数

由上面,我们知道$x$中最多只包含一个大于$\sqrt{x}$的质因子,如果有两个就大于$x$了,矛盾。所以我们先枚举小于等于$\sqrt{x}$的质因子,再特判一下大于$\sqrt{x}$的质因子即可。代码如下:

 1 void solve(int n){
 2     for(int i = 2; i <= n / i ; i ++)
 3     {
 4         if( n % i == 0){
 5             int s = 0;
 6             while(n % i == 0){
 7                 n /= i;
 8                 s ++;
 9             }
10             cout << i << " " << s << endl;
11         }
12     }
13     if(n != 1)cout << n << " " << 1 << endl;
14 }

 

   三:(1)筛法求质数

思想是,将$2\sim n$之间的数枚举,从前往后,依次将每一个数的倍数筛掉,用一个$primes$数组存储质数,代码如下:

 1 void get_primes(int n)
 2 {
 3     for (int i = 2; i <= n; i ++ )
 4     {
 5         if (st[i]) continue;
 6         primes[cnt ++ ] = i;
 7         for (int j = i; j <= n; j += i)
 8             st[j] = true;
 9     }
10 }

当$i = 2$,循环$\frac{n}{2}$次, 当$i = 3$ ,循环$\frac{n}{3}$次。所以一共循环$\frac{n}{2}+\frac{n}{3}+\frac{n}{4}+\cdot \cdot \cdot \frac{n}{n}=n\left ( \frac{1}{2}+\frac{1}{3}+\frac{1}{4}+\cdot \cdot \cdot +\frac{1}{n} \right )$,当$n$趋于无穷时,调和级数趋于$lnn + c$。

所以该算法的时间复杂度为$O(nlogn)$。这个复杂度是计算将每一个数的倍数筛掉的时间复杂度,而代码中的只将素数的倍数筛掉的复杂度会更低一些,为$O(nloglogn)$。

($1 \sim  n$ 中有$\frac{n}{lnn}$个素数)。

  

  (2)线性筛法:

 1 void get_primes(int n)
 2 {
 3     for (int i = 2; i <= n; i ++ )
 4     {
 5         if (!st[i]) primes[cnt ++ ] = i;
 6         for (int j = 0; primes[j] <= n / i; j ++ )
 7         {
 8             st[primes[j] * i] = true;
 9             if (i % primes[j] == 0) break;
10         }
11     }
12 }

将每一个质数加入,然后该质数去筛掉该质数的倍数。当$i \;mod\; primes[j] == 0$时,$primes[j]$一定是$i * primes[j]$的最小质因子,也一定是$i$的最小质因子。当$i \;mod\; primes[j] != 0$时,说明$primes[j]$小于$i$的所有质因子,所以$primes[j]$也一定是$primes[j] * i$的最小质因子。对于一个合数$x$,假设$primes[j]$是他的最小质因子,当$i$枚举到$\frac{x}{primes[j]}$的时候,($\frac{x}{primes[j]}$一定比$x$先枚举到),$x$就会在循环内被筛掉。由于每一个数只有一个最小质因子,所以是线性的。

 

 

 

 

 

posted @ 2019-11-28 11:36  dzcixy  阅读(300)  评论(0)    收藏  举报