素数专题(未完待续)

素数

一、素数与合数的定义

  设整数 \(p\ne0\),\(±1\). 如果它除了显然约数 \(±1\), \(±p\) 外没有其它约数, 那么 \(p\) 就称为不可约数,也叫素数. 若 \(a\ne0\),\(±1\)\(a\) 不是不可约数,则称 \(a\)合数. (没有特殊说明, 素数总是指正的)

定理 设整数 \(a\geqslant2\), 那么 \(a\) 一定可以表示为素数的乘积(包括 \(a\) 本身是不可约数),即
\[a = p_{1}p_{2}···p_{s},\]
其中 \(p_{j}(1\leqslant j\leqslant s)\) 是不可约数.

二、有关素数的重要推论 (设整数 \(a\geqslant2\))

(i) 若 \(a\) 是合数, 则必有不可约数 \(p\nmid a\), \(p\leqslant \sqrt{a}\) ;
(ii) 若 \(a\)定理中的表示式,则必有不可约数 \(p\nmid a\), \(p\leqslant a^{1/s}\) .

三、有关素数的算法

1.素性测试 \(O(n\sqrt{n})\)

//假设输入的数为正数
bool is_prime(int n) {
  for (int i = 2; i * i <= n; i++) {
    if (n % i == 0) return false;
  }
  return n > 1; //特判1
}

2.埃拉托斯特尼筛法 \(O(nloglogn)\)

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 10000;

//埃拉托斯特尼筛法(sieve of Eratosthenes), 复杂度 O(nloglogn)
int prime[N], cnt = 0;  //prime数组用于存放素数, cnt用于统计素数的个数
bool is_prime[N];       //is_prime数组用于标记当前数是否被筛选过
void sieve_of_Eratosthenes(int n) {
    memset(is_prime, 1, sizeof is_prime);  //初始化
    is_prime[0] = is_prime[1] = false;     //将 0 和 1 标记为已筛选
    for (int i = 2; i <= n / i; i++)       //i循环到sqrt(n)足矣
        if (is_prime[i]) {
            prime[cnt++] = i;
            for (int j = i * i; j <= n; j += i)  //因为2,3,4,...,i-1的倍数之前已经筛过了,直接从i的倍数开始筛
                is_prime[j] = false;             //只要是i的倍数均标记为非素数
        }
    return;
}

3.欧拉筛法(Sieve of Euler) 几乎是\(O(n)\)

//欧拉筛法(sieve of Euler), 复杂度 几乎是O(n)
int primes[N], cnts = 0;       //primes数组用于存放素数, cnts用于统计素数的个数
bool is_notprime[N] = {1, 1};  //首先将 0 和 1 初始化为非素数
void sieve_of_Euler(int n) {
    for (int i = 2; i < n; i++) {
        if (!is_notprime[i]) primes[cnts++] = i;
        for (int j = 0; j < cnts && i * primes[j] < n; j++) {
            is_notprime[i * primes[j]] = 1;
            if (!(i % primes[j])) break;    //确保每个合数只会被它的最小质因子筛除,并且只筛除一次
        }
    }
}

posted @ 2020-10-18 07:57  Xiezeju  阅读(147)  评论(0编辑  收藏  举报