杂
学数论 心情复杂 没什么好说的 , , ,, 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.