素数

学数论 心情复杂 没什么好说的 , , ,, z h 大佬!!


素数

定义

就是质数 , ( 1不是素数) , 一个比 1 大的整数若没有约数(1不算) , 称为合数

整除

(a=kd) ( (k) 为整数) , 则称 (d) 整除 (a) , 记做 (d)

素数计数函数

小于/等于 (x) 的素数的个数 , 用 (pi(x)) 表示 , 随着 (x) 的增大 , 有这样的近似结果 :

[pi(x) sim frac{x}{ln(x)} ]

素数筛法

(LARGE暴力) (O(nsqrt n))

对于检验一个数是不是素数 , 暴力做法 --- 枚举 ,, 稳妥 , 但没必要 , 显然 , 若 (x)(a) 的约数 , 那么 (frac{a}{x}) 也是 (a) 的约数 , 所以对于每对 ((x, frac ax)) , 只需检验其中一个就可以了 , 其中较小的那个约数在区间 ([1,sqrt a]) 里 , 故单次判断的时间复杂度为

bool isPrime(a) {
    if(a < 2) return 0; // 1是约数
    for(int i = 2; i * i <= a; i ++) 
        if(a % i == 0) return 0;
    return 1;
}

(LARGEmathfrak{Eratosthenes} 筛法 (埃拉托斯特尼筛法 / 埃氏筛)) (O(n~log~log~n))

考虑到对于合数 (x) , (x) 的倍数一定也是合数 , 从小到大筛 , 顺手把当前数的倍数标记为合数 , 最后没被标记 (tag[i] = 1) 的数为素数 , 并且都存到了 (prime) 数组里

void Eratosthenes(int n) { 
    int p = 0;
    for(int i = 0; i <= n; i ++) tag[i] = 1;
    tag[0] = tag[1] = 0; //以上为初始化标记
    for(int i = 2; i <= n; i ++) {
        if(tag[i]) {
            prime[p ++] = i; //p为当前素数数量
            for(int j = i * i; j <= n; j += i) tag[j] = 0; 
            //已经筛过了2到i-1的倍数,所以直接从i开始
        } 
    }//需要返回质数个数的话写成int的函数 return p 即可
}

(LARGEmathfrak{Euler} 筛法 (欧拉筛/线性筛)) (O(n))

考虑到埃氏筛把一些合数重复筛到 , 所以还不够优 , 在埃氏筛的基础上,欧拉筛思想为:每个合数只被它的最小质因子筛到一次

int pri[maxx], tag[maxx];
void Euler(int maxx) {
    int cnt(0);
    for(int i = 2; i <= maxx; i ++) {
        if(!tag[i]) pri[++ cnt] = i;
        for(int j = 1; j <= cnt, i * pri[j] <= maxx; j ++) {
	    tag[i * pri[j]] = 1;
            if(i % pri[j] == 0) break;
        }
    }
}

end.

而我们终其一生,都希望能成为更好的人。
原文地址:https://www.cnblogs.com/moziii/p/13281462.html