【数论】【算法】质数及相关

定义

若一个正整数无法被除了 \(1\) 和他自身之外的任何正整数整除,则该数为质数,否则为合数。

判定

\(O(n)\)

bool isprime (int x) {
    for (int i = 2; i*i <= n; ++ i) if (!(x%i)) return 0;
    reutrn 1;
}

由于正整数的因数对于它的平方根对称(意会一下,一个小于 \(\sqrt n\) 的数必须乘上一个大于 \(\sqrt n\) 的数才能等于 \(n\)),所以只需要对小于 \(\sqrt n\) 的数进行判断。

筛取

\(1\sim n\) 范围内的质数。

  • 埃式筛

时间复杂度 \(O(n \log \log n)\)

(其实 \(\log \log 10^9 < 5\),已经是常数级别。)

点击查看代码
int n;
bool inp[man];
vector<int> prime;
int main () {
    scanf("%d", &n);
    inp[0] = inp[1] = 1;
    prime.push_back(2);
    for (int i = 3; i <= n; i += 2) {
        if (!inp[i]) {
            prime.push_back(i);
            for (int j = i*i; j <= n; j += i) inp[j] = 1;
        }
    }
    for (int x : prime) printf("%d ", x);
    return 0;
}

中间部分 i - j 循环:这是从 i*i 开始的。是因为 2*i3*i……(i-1)*i 在之前已经被 23……i-1 筛过。

显然除了 \(2\) 以外的偶数都是合数。

(若不需要 prime 数组,则可以令 i <= sqrt(n)。)

  • 欧拉筛(线性筛,xxs)

在埃式筛中虽然已经进行了优化,但是例如 \(12\) 这样的数还是会被 \(2 \times 6\)\(3 \times 4\) 筛两遍。

对于一个数进行质因数分解,即 \(12 = 2 \times 2 \times 3\),且令其只被他的最小质因数筛取,即 \(12\) 只被 \(2 \times 6\) 筛。

点击查看代码
int n;
int mpf[man];
bool inp[man];
vector<int> prime;
int main () {
    scanf("%d\n", &n);
    inp[0] = inp[1] = 1;
    for (int i = 2; i <= n; ++ i) {
        if (!inp[i]) 
            prime.push_back(i), mpf[i] = i;
        for (int pri_j : prime) {
            if (i*pri_j > n) break;
            inp[i*pri_j] = 1, mpf[i*pri_j] = pri_j;
            if (i%pri_j) break;
        }
    }
    for (int x : prime) printf("%d ", x);
    return 0;
}

中间部分 i - pri_j 循环 i % pri_j 判断语句:i 之前已被 pri_j 筛过了。
由于 pri 里面质数是从小到大的,所以 i 乘上其他的质数的结果一定也已经被 pri_j 的倍数筛掉,就不需要在这里筛,直接结束即可。

Extra

注意到欧拉筛求素数的同时也得到了每个数的最小质因数在 mpf 中。

质因数分解

若要分解正整数 \(N\)

从小到大判定 \(2 \sim \lfloor \sqrt{N} \rfloor\) 中的每个数 \(d\),若 \(d\) 能整除 \(N\), 则从 \(N\) 中除去所有的 \(d\),同时记录。

\(2 \sim \lfloor \sqrt{N} \rfloor\) 中没有可以整除 \(N\) 的书,则 \(N\) 为质数(见判定)。

应用

例题【Prime Distance】

本题的数据范围过于大,\(2147483647\) 是无法在 \(O(n)\) 时间内检测所有质数的。

可以观察到,\(L\sim R\) 的数据范围较小,所以可以每次查询 \(L\sim R\) 内的所有质数,需限制在 \(O(n)\) 内。

\(\sqrt{2147483647} \approx 46341\),所以只要找到所有不大于 \(46341\) 的质数再对 \(L\sim R\) 中每个数进行判定即可,在判定时找到距离最大和最小的质数。

单次复杂度 \(O(R-L)\)

点击查看代码
/*
compiling in 
ide 
g++ test.cpp -o test && ./test
*/
#include <bits/stdc++.h>
#include <bits/extc++.h>
namespace {
#define filein(x) freopen(x".in", "r", stdin)
#define fileout(x) freopen(x".out", "w", stdout)
#define file(x) filein(x), fileout(x)
using namespace std;
using namespace __gnu_pbds;
#define ll long long
#define db double
#define un unsigned
#define ui un int
#define ull un ll
#define udb un db
// template <typename T>
// #define pair<T> pair<T, T>
#define pii pair<int, int>
#define pll pair<ll, ll>
#define pdb pair<db, db>
#define mp(x, y) make_pair(x, y)
const int man = 1e6+10;
}

ui l, r, n = sqrt(2147483647);
ll res;
ui v[man], mpf[man];
vector <ui> pri;
vector <pair<ui, ui> > pril;
int main () {
    // file("test");
    for (ll i = 2; i <= n; ++ i) {
        if (!v[i]) mpf[i] = i, pri.push_back(i);
        for (ll j : pri) {
            if (i*j > n) break;
            v[i*j] = 1;
            if (!(i%j)) break;
        } }
    while (scanf("%u%u", &l, &r) != EOF) {
        int minn = 1e6+10, maxx = 0;
        pii mi, ma;
        memset(v, 0, sizeof(v));
        pril.clear();
        for (int i = l; i <= r; ++ i) {
            for (int j : pri) if ((!(i%j) && i!=j) || i==1) {
                v[i-l] = 1;
                break;
            }
            if (!v[i-l]) 
                if (pril.size() >= 1) {
                    int la = pril.back().first;
                    if (minn > i-la) 
                        minn = i-la, mi = mp(la, i);
                    if (maxx < i-la) 
                        maxx = i-la, ma = mp(la, i);
                    pril.push_back(mp(i, i-la));
                }
                else pril.push_back(mp(i, 0));
        }
        if (pril.size() >= 2) 
            printf("%d,%d are closest, %d,%d are most distant.\n", mi.first, mi.second, ma.first, ma.second);
        else puts("There are no adjacent primes.");
    } return 0;
}
// --- 
posted @ 2023-11-17 21:05  STA_Morlin  阅读(8)  评论(0编辑  收藏  举报