1、质数判断
bool isPrime(int n) { if (n < 2) return false; for (int i = 2; i <= n / i; i++) if (n % i == 0) return false; return true; }
2、埃拉筛
const int N = 1e5 + 10; int primes[N], cnt; // primes[]存储所有素数 bool st[N]; // st[x]存储x是否被筛掉 void get_primes(int n) { for (int i = 2; i <= n; i++) if (!st[i]) { primes[cnt++] = i; //记录素数 for (int j = 2 * i; j <= n; j += i) //成倍数的标识 st[j] = true; } }
3、欧拉筛
int primes[N], cnt; // primes[]存储所有素数 bool st[N]; // st[x]存储x是否被筛掉 void get_primes(int 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] = true; if (i % primes[j] == 0) break; } } }
代码解析:
如果\(i\%primes[j]==0\)成立,那么\(i\)一定是一个合数,可以把\(i\)分解成\(a*b\)的形式,
并且\(a,b\)中有一个数一定是质数(唯一分解定理).则有\(i*primes[j]=a*b*primes[j]\),
假设\(a\)是\(i*primes[j]\)的最小质因子,那么遍历到\(b*primes[j]\)时,一定能把\(i*primes[j]\)标记成合数,此时\(a\)是\(i*primes[j]\)的最小质数,所以在遇到\(i\)的时候直接跳出即可。
举个栗子:\(i = 8 ,j = 0\),\(prime[j] = 2\),此轮会把\(i*primes[j]=8*2=16\) 筛掉, 如果不跳出循环,\(primes[j+1] = 3\),\(8 * 3 = 2 * 4 * 3 = 2 * 12\),它会还要去筛掉\(24\),而\(24\)在\(i = 12\)时会筛掉(最小质数因子筛掉思想!),这样就有重复了,不行!!
为什么\(if(i\%primes[j]==0) break\);在\(is\_prime[i*primes[j]]=false\);的后面呢?
此时是因为,我们遍历到的第一个素因子其实是\(2\),这个素因子是最小的,
所以第一次的时候\(i*primes[j]\)一定是被它最小的素因子筛去的.
4、分解质因数
void divide(int x) { for (int i = 2; i <= x / i; i++) //到sqrt就够了 if (x % i == 0) { int s = 0; while (x % i == 0) x /= i, s++; cout << i << ' ' << s << endl; } //如果还没有除开,就是还需要写一个 if (x > 1) cout << x << ' ' << 1 << endl; cout << endl; }