标签:prime 存储 out for 复杂 log 筛法 nlogn bre
一:判定质数
要判断一个数是不是质数,只需遍历小于等于它的所有数,如果它能被除了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,那么x/d也是x的约数,所以我们只需要枚举较小的一个就可以了,即d < x/d ,即我们只需枚举到√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(√n)。
二:分解质因数
由上面,我们知道x中最多只包含一个大于√x的质因子,如果有两个就大于x了,矛盾。所以我们先枚举小于等于√x的质因子,再特判一下大于√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~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,循环n / 2次, 当i = 3 ,循环n / 3次。所以一共循环n / 2 + n / 3 + n / 4 + ....n / n = n(1 / 2 + 1 / 3 + 1 / 4 + ... 1 / n),当n趋于无穷时,调和级数趋于lnn + c。
所以该算法的时间复杂度为O(nlogn)。这个复杂度是计算将每一个数的倍数筛掉的时间复杂度,而代码中的只将素数的倍数筛掉的复杂度会更低一些,为O(nloglogn)。
(1 ~ n 中有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 % primes[j] == 0时,primes[j]一定是i * primes[j]的最小质因子,也一定是i的最小质因子。当i % primes[j] != 0时,说名primes[j]小于i的所有质因子,所以primes[j]也一定是primes[j] * i的最小质因子。对于一个合数x,假设primes[j]是他的最小质因子,当i枚举到x / primes[j]的时候,(x / primes[j]一定比x先枚举到),x就会在循环内被筛掉。由于每一个数只有一个最小质因子,所以是线性的。
标签:prime 存储 out for 复杂 log 筛法 nlogn bre
原文地址:https://www.cnblogs.com/1-0001/p/11948829.html