素数

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


素数

定义

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

整除

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

素数计数函数

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

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

素数筛法

\(\LARGE暴力\) \(O(n\sqrt 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;
}

\(\LARGE\mathfrak{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 即可
}

\(\LARGE\mathfrak{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.

posted @ 2020-07-10 21:48  hulne  阅读(1062)  评论(3编辑  收藏  举报