数论(二)

素数

。如果 除了 之外没有别的因数,则称 素元。正的素元称为素数

算术基本定理

任何非零整数 都有素因子分解

其中 (当 时右式规定为 ), 是相异素数,,而且此分解不论顺序是唯一的。

证明 关于分解的存在性,处理 的情形即可。我们寻求形如 的分解。如果 既非 又非素数,则分解为 ,其中 。继续对 递归地操作,最终可表 为若干个素数的乘积,容许重复。

唯一性仍可简化到 的情形。设 ,其中 是相异素数, 也是相异素数,而 。注意到 当且仅当 ,此时两边都是 。故以下不妨设

由于 ,反复应用欧几里得引理可知存在 使得 ;这进一步蕴含 。重排下标后不妨假设 ,必要时等号两边互换,不妨假设 。于是

再次应用欧几里得引理可见 不整除左式,故 。按此递归地论证,即得分解的唯一性。

算术基本定理的推论

  • 对于任何素数 和非零整数 ,我们有 当且仅当 的素因子分解中出现,相应的指数 由以下性质唯一确定:,数论中的标准记法如下

    • 为素数,我们以符号 表达
  • 考虑正整数 ,其中 是相异素数而 ,则

    • 对于任意多个正整数的 也有类似结果。

有无穷多个素数

素数列 是数论关切的基本对象;这方面最古老也是最基础的结果是

存在无穷多个素数。

证明 对任意一列素数 ,考虑

,而且它不被 中任一个素数整除。因此 的素因子分解中必有不同于 的素数。

给定正整数 ,找出不超过 的全部素数。

素数筛

我们试图制造一个筛子。

我们把整数 放进筛子,启动筛子。筛子会把其中的合数全都筛出去,素数全都保留。

筛完之后,筛子里剩下的就是不超过 的全部素数。

埃氏筛

线性筛

Lucy_Hedgehog 算法

给定正整数 ,求不超过 的素数有多少个。

  • 我们以 表示第 个素数。例如
  • 是实数,以 表示不超过 的素数的个数。
    例如:,若
    我们要计算

计算

对于实数 和正整数 ,定义 为从区间 中去掉最小素因子 的合数之后,剩下的整数的数量。此外,定义

是不超过 的最大的素数,即 ,那么

是正整数。有以下递推式

证明:根据定义,我们有

,即 时,区间 上没有最小素因子 的整数,此时有

,即 时,区间 上最小素因子 的整数的个数是

显然有

对于任意正整数

用带余除法表作 ,其中 。再设 用带余除法表作 ,其中 。于是

代入 ,得

显然有 ,我们只需要证明 。我们有

计算

给定正整数 。令 。根据递推式

计算

我们需要计算的子问题形如 ,其中 满足

  • 中一些相异的素数的乘积。因而有

是正整数,定义集合

例如

是正整数。令 。那么集合 里有 个元素,从大到小排列是

其中 是连续的。

里,我们把 称为大值,把 称为小值

是正整数,,那么

可知 ,因此 。下面证明等号不能成立,从而得到严格大于。

假设 ,即 ,即

于是我们有 ,即 ,又 ,所以

另一方面,根据题设,有 ,所以 ;结合 式的右边 ,得 ,所以 ,即

所以 不存在。

是正整数,。那么

也就是说,对于 里的每个大值,若把它表作 ,那么 是唯一的。

是正整数,。那么

,我们证明

根据上一个命题,有 ,即 ,所以

,所以

.

.

里的元素从小到大排列是

其中, 可能等于

long long prime_count(long long n) {
    const int k = (int) sqrt(n);
    vector<long long> v; // n, n/2, n/3, ..., n
    for (int i = 1; i <= k; i++)
        v.push_back(n / i);
    for (int i = n / (k + 1); i >= 1; i--)
        v.push_back(i);
    // 对于 i = 1, 2, ..., k+1 有 n/i == v[i-1]。
    // 对于 i = 1, 2, ..., k 还有,i 是唯一的满足 n/d == n/i 的正整数 d。我们称这些值为大值。
    const int m = (int) v.size();
    vector<long long> f(m);
    for (int i = 0; i < m; i++)
        f[i] = v[i] - 1;
    
    auto [p, lpf] = get_primes(k);
    const int s = (int) p.size();
    for (int i = 0; i < s; i++) {
        f[0] -= f[p[i] - 1] - i;
        if (i == s - 1) break;
        const long long L = (long long) p[i] * p[i];
        const int lim = k / p[i];
        for (int j = p[i + 1] - 1; j < m && v[j] >= L; j++) {
            if (j < k && lpf[j + 1] < p[i + 1]) continue;
            if (j + 1 <= lim) {
                f[j] -= f[(j + 1) * p[i] - 1] - i;
            } else { // v[j] / p[i] <= k
                f[j] -= f[m - v[j] / p[i]] - i;
            }
        }
    }
    return f[0];
}

时间:

是正整数。对于任意正整数 ,定义 中大于等于 的元素的个数,那么

是正整数。若

是正整数,。那么

题设 ,即 ,即

又因为 ,所以 。于是有 ,由于 ,有

结合,得 ,即

,命题得证。

积性函数的前缀和

我感觉这其实就是在应用容斥原理。这里值得深挖。