首页 > 其他分享 >素数

素数

时间:2024-11-29 19:43:30浏览次数:9  
标签:mathbb int 合数 leq 素数 复杂度 质数

可能出现“质数”、“素数”混用的情况,见谅。

定义

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

注意到在整个自然数集合中,质数数量不多、分布稀疏,对于一个 足够大 的 \(N \in \mathbb{Z}\),\(\leq N\) 的质数大约有 \(\frac{N}{\ln N}\) 个。换句话说,每 \(\ln N\) 个数中大约有 \(1\) 个质数。

质数判定与筛选

试除法

我们知道若 \(N \in \mathbb{Z}\) 且 \(N\) 为合数,则必定存在一个能整除 \(N\) 的数 \(M\) 满足 \(2 \leq M \leq \sqrt{N}\)。

可以写出代码:

bool IsPrime(int x) {
    if (x == 0 || x == 1)
        return 0;
    for (int i = 2; i * i <= x; i++) {
        if (x % i == 0)
            return 0;
    }
    return 1;
}

基于随机化的判定有 Miller-Robbin

Eratosthenes

思想是对于任意 \(x\) 的倍数 \(x, 2x, 3x, \dots\) 都不是质数,所以从 \(2\) 开始倍数筛掉,往后若一个数 \(x\) 尚未被标记,意味着其不能被 \(\forall [2, x - 1]\) 整除,则其为质数。

然后同上试除法,为了防止形如 \(6 = 3 \times 2\) 同时被 \(2, 3\) 筛两次的情况(小于 \(x^2\) 的数 \(x\) 的倍数在扫描更小的数就已经筛过了),从 \(x^2\) 开始,标记 \(x^2, (x + 1)x, \dots, \lfloor \frac{N}{x} \rfloor x\) 即可。

void Prime(const int n) {
    memset(v, 0, sizeof(v));
    for (int i = 2; i <= n; i++) {
        if (v[i])
            continue;
        p[++tot] = i;
        for (int j = i; j <= n / i; j++)
            v[i * j] = 1;
    }
}

复杂度为 \(O(\sum_{p \leq N, p \in \mathbb{P}} \frac{N}{p}) = O(N \log \log N)\),接近线性,是 OI 中最常见的筛法。

线性筛

我们是怎么优化暴力筛的?通过枚举倍数来减少总的枚举次数。但是优化后我们的埃氏筛还是会重复标记某些合数,例如 \(12\) 会被 \(2 \times 6\) 和 \(3 \times 4\) 同时标记。那我们能否唯一确定出一种筛选出某个数的做法:即我们 能否确定某个数唯一产生的方式

我们正式引入线性筛:线性筛通过“从小到大累积质因子”的方式标记每个合数,这里直接给出易懂的代码:

处理的手段其实就是通过确定唯一产生数的方式来确定唯一的“遍历”方式。

int v[N], p[N];

void Prime(const int n) {
    m = 0;
    memset(v, 0, sizeof(v));
    for (int i = 2; i <= n; i++) {
        if (!v[i]) { v[i] = i; p[++m] = i; }    // 质数
        // 给当前的数 i 乘上一个质因子
        for (int j = 1; j <= m; j++) {
            // i 有比 p[j] 更小的质因子,或者已经超出了 n 的范围
            if (p[j] > v[i] || p[j] > n / i)
                break;
            // p[j] 是合数 i * p[j] 的最小质因子
            v[i * p[j]] = p[j];
        }
    }
}

复杂度为 \(O(n)\),真正的线性筛法。

算数基本定理

这非常重要。

任何一个大于 \(1\) 的正整数都能唯一分解有限个质数的乘积,形式化地:

\[N = p_1^{c_1} p_2^{c_2} \cdots p_m^{c_m} \]

其中 \(c_i \in \mathbb{Z}, p_i \in \mathbb{P}, p_1 \lt p_2 \lt \cdots \lt p_m\)。

结合试除法和埃氏筛我们就可以进行一个质因数的分解,复杂度为 \(\sqrt{N}\)。

void DivideNum(const int n) {
    m = 0;
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) {   // i 是质数
            p[++m] = i;
            c[m] = 0;
            while (n % i == 0) { c /= i; c[m]++; }      // 抹掉所有 i
        }
    }
    if (n > 1) { p[++m] = n; c[m] = 1; }    // n 是质数
}

有一种效率更高的 Pollard's Rho 用于优化复杂度。

标签:mathbb,int,合数,leq,素数,复杂度,质数
From: https://www.cnblogs.com/xsyc/p/18577417

相关文章

  • C语言实例之10求0-200内的素数
    1.素数素数(Primenumber),也叫质数,是指在大于1的自然数中,除了1和它自身外,不能被其他自然数整除的数。例如2、3、5、7、11等都是素数,而4能被2整除、6能被2和3整除,所以它们不是素数。2.素数的特性与判断思路素数是指在大于1的自然数中,除了1和它自身外,不......
  • 0015 判断输入的数是不是素数-控制台程序-极语言教程
    小程序初始启动写格式("请输入大于1并且小于等于2147483647的正整数进行素数判断:\r\n")循环{整数输入数,计数,判断数=1,开始时间=0,结束时间=0,需要时间=0读格式("%d",&输入数)开始时间=开机毫秒循环于(计数=2;计数<输入数;计数++){......
  • 程序设计C语言(输出素数)
    //输出100~200之间的素数intmain(void){intnum,i;for(num=100;num<=200;num++){for(i=2;i<num;i++){if(num%i==0){break;}if(i==num-1){printf("%d\n",nu......
  • 泛型编程素数
    古希腊的数论目标图形数埃拉托斯特尼筛法准备工作代码测试埃拉托斯特尼Python比较代码Python改成2N应用素数的判断匹配——散列法扩展头尾素数验证目标用埃拉托斯特尼筛法找201前的素数。把STL改成Python实现,对比之前的求素数算法。运行结果图形数毕达哥拉斯......
  • JZOJ【基础】素数密码学//注意:后面有彩蛋
    VIP以下是一个C++程序,该程序接受一个合数n作为输入,并尝试将其分解为两个素数的乘积。如果成功找到这样的分解,它将输出所有可能的分解方式;如果找不到,它将输出"error"。#include<bits/stdc++.h>usingnamespacestd;boolisPrime(intnum){if(num<=1){ returnfa......
  • 素数筛法算法
    素数定义:素数是指在大于1的自然数中,除了1和它本身外,没有其他因数的数。换句话说,素数只有两个正因数:1和它本身。注意:0和1既不是质数也不是合数。inlineboolisprime(intx){for(inti=2;i<=x-1;++i){if(x%i==0)return0;return1;}}in......
  • 计算嵌套列表中的元素数量
    我试图计算嵌套列表中的元素数量,该列表如下所示:[(1944,['HughesH']),(1940,['HillDK','CrawfordGN','GreeneHS','MyersJ','BurrGO']),(1941,['McClungCE','SumnerFB','Gat......
  • 求1000以内所有恰好能分解成10组两个素数之和
    要求根据哥德巴赫猜想,任意一个大偶数都可以分解为两个素数之和。但许多偶数分解为两个素数之和并不是唯一的。请编写函数fun,其功能是:求1000(不包括1000)以内的所有恰好能分解成10组两个素数之和(5+109和109+5被认为是同一组)的偶并依次存入数组a中并在屏幕上打印出来,打印时......
  • 素数个数[中秋快乐~]
    题目描述编程求 2 ~ n (包括 n)中有多少个素数。输入格式输入 n(2≤n≤50000)。输出格式素数个数。输入数据110 输出数据14代码#include<bits/stdc++.h>usingnamespacestd;intmain(){intn,ans=0;cin>>n;for(inti=2;i<=n;i++){......
  • 获取一定范围内的素数
     方法一:使用外部循环指定标签publicclassPrime{publicstaticvoidmain(String[]args){//目标:完成找素数//1.定义一个for循环,产生101——200之间的每个数据intcount=0;OUT://为外部循环指定标签for(inti=10......