3. 有关素数的算法

1. 素性判定:

  质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数;否则称为合数。

  如果 d 是 n 的约数, 那么 n / d 也是 n 的约数,可知 min (d, n / d) ≤  √n , 那么只要检查 2 ~ √n 的整数即可。同理可知整数分解和约数枚举都可以在 0(√n) 的时间复杂度下完成。

//素性测试
bool isPrime (int n) {
    for (int i = 2; i * i <= n; i++)
        if (n % i == 0) 
            return false;
    return n != 1;
} 

//约数枚举
vector<int> divisor (int n) {
    vector<int> res;
    for (int i = 1; i * i <= n; i++) {
        if (n % i == 0){
            res.push_back(i);
            if (i != n / i)
                res.push_back(n / i); 
        }
    }
    return res;
} 

//整数分解
map<int, int> primefactor (int n) {
    map<int, int> res;
    for (int i = 2; i * i <= n; i++) {
        while (n % i == 0){
            ++res[i];
            n /= i;
        }
    }
    if (n != 1) res[n] = 1;
    return res;
} 

整数分解(integer factorization)又称素因数分解(prime factorization),是将一个正整数写成几个约数的乘积

整数分解 map里存放的是 n 的素约数。

2. 埃氏筛法  0(n log log n)

  用来解决 n 以内有多少素数。

  先将 2 到 n 范围内的所有整数打表, 其中最小的 2 是素数。 将表中所有 2 的倍数都划去。表中剩余最小的 3 是素数,再把表中所有 3 的倍数都划去。以此类推, 如果表中剩余的最小数字是 m 时, m 就是素数。 像这样反复操作,就能依次枚举 n 以内的素数。

int prime[MAX_N];         //第 i 个素数 
bool isPrime[MAX_N + 1];  // true 表示 i 是素数
// 返回 n 以内素数的个数
int sieve (int n) {
    int p = 0;
    fill (isprime, isprime + n, true);
    isPrime[0] = isPrime[1] = false;
    for (int i = 2; i <= n; i++) {
        if (isPrime[i]){
            prime[p++] = i;
            for (int j = 2 * i; j <= n; j += i)
                isPrime[j] = false;
        }
    }
    return p;
} 

3.区间筛法

   区间 [a, b) , b 以内的合数的最小质因数一定不超过 √b 。 也就是说 如果有 √b 以内的素数表, 就可以吧埃氏筛法用在 [ a, b ) 上,也就是说, 先分别做好 [ 2, √b ) 和 [ a, b) 的表, 然后从 [ 2, √b ) 的表中筛得的素数的同时,也将其倍数从 [a, b) 的表中划去, 最后剩下的就是 [a, b) 内的素数。

typedef long long ll;
//区间范围[a, b) 
bool is_prime[MAX_L];
bool is_prime_small[MAX_SQRT_B];

void segment_sieve(ll a, ll b) {
    for (int i = 0; (ll) i * i < b; i++) is_prime_small[i] = true;
    for (int i = 0; i < b - a; i++) is_prime[i] = true;
    
    for (int i = 2; (ll)i * i < b; i++) {
        if (is_prime_small[i]) {
            //筛(2, sqrt(b) ) 
            for (int j = 2 * i; (ll)j * j < b; j += i)
                is_prime_small[j] = false;
            //筛 (a, b) 
            for(ll j = max(2LL, (a + i - 1) / i) * i; j < b; j += i)
                is_prime[j - a] = false;
        }
    }
}
原文地址:https://www.cnblogs.com/astonc/p/10657179.html