【重拾算法第一天】质数约数欧拉筛 埃氏筛GCD

1.素数

素数(Prime Number)是指大于1的自然数,只有两个正因数:1和它自身。换句话说,素数是不能被其他自然数整除的数。

1.1小素数的判定

判定一个数是否为素数 ,当N ≤  10^{12}时, 用试除法 , 当n > 10^{12} 时 , 用Miller_Rabin算法

根据素数的定义,可以直接得到试除法 , 用[2,n - 1] 内的所有数着除n,如果不能整除 , 就是素数,很容易发现 可以把[2 , n - 1] 缩小到 , [2,\sqrt{n}]

试除法的时间复杂度为O(n),N ≤  10^{12}时够用 ,  以下为试除法的实现代码:

#define int long long
bool is_prime(int n)
{
    if(n <= 1) return false;
    for(int i = 2;i * i <= n;i ++)
    {
        if(n % i == 0) return false;
    }
    return true;
}
//i * i <= n 也可以写成 i < n / i

1.2大素数的判定

本章介绍大素数的判定的两种方法

如果N 非常大  试除法就不够用了

一般采用Miller_Rabin素行测试算法  ,由于这个算法过于复杂 就不在这里介绍这个算法了

2.分解质因数

什么是质因数?

质因数(Prime Factor)是指一个整数的质数因子。换句话说,质因数是能够整除该整数的质数。每个大于1的自然数都可以被唯一分解为质因数的乘积,这称为质因数分解。

void divide(int x)
{
    for(int i = 2;i <= x / i;i ++)
    {
        if(x % i == 0)  //以x为底数
        {
            int s = 0; //s为指数
            while(x % i == 0) x /= i , s++;
            cout << i << ' ' << s << endl;
        }
    }
    if(x > 1) cout << x << ' ' << 1 << endl;
    cout << endl;
}

3.素数筛

主要用于筛选1 ~ n 中的素数的个数

有两种方法 :

3.1.埃氏筛发(传统的  时间复杂度O(nlognlongn))

代码实现:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int prime[N]; //存储素数  visit[i]为false的项
bool vis[N];  //true表示被筛掉 不是素数
int E_sieve(int n)  //埃氏筛法
{
    int k = 0; //统计个数
    for(int i = 0;i <= n;i ++) vis[i] = false;
    for(int i = 2;i <= n;i ++)
    {
        if(!vis[i])
        {
            prime[k++] = i;
            for(int j = 2 * i;j <= n;j += i)
            // 可以优化成 j = i * i
            {
                vis[j] = true;
            }
        }
    }
    return k;
}
int main()
{
    int n;
    cin >> n;
    cout << E_sieve(n) << endl;
    return 0;
}

3.2.欧拉筛(时间复杂度O(n))

欧拉筛的原理:

欧拉筛是一种线性筛法 , 能在O(n) 的线性时间求得1~N内所有的素数  欧拉筛是对埃氏筛的一种改进

原理:一个合数肯定有一个最小的质因数;让没个合数只被他的最小质因数筛选一次 ,达到不重复筛的目的;

具体操作:

1:逐一检查2~n的所有数  第一个检查的是 2 , 他是第一个素数

2:当检查到第i个数时,利用已经求得的素数去筛掉对应的合数x , 而且是用x的最小质因数去筛

代码实现:

#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 10;  // 定义常量N为1000010,表示素数的上限
int prime[N];            // 存储素数的数组,visit[i]为false的项
bool vis[N];             // vis[i]表示i是否被筛掉,true表示i不是素数

// 欧拉筛法,返回小于等于n的素数个数
int euler_sieve(int n) {
    int cnt = 0;  // 计数器,用于记录素数的个数
    memset(vis, 0, sizeof(vis));  // 初始化vis数组,所有项设为false
    memset(prime, 0, sizeof(prime)); // 初始化prime数组

    // 从2开始,遍历到n
    for (int i = 2; i <= n; i++) {
        // 如果vis[i]为false,说明i是一个素数
        if (!vis[i]) {
            prime[cnt++] = i;  // 将素数i存入prime数组,并增加计数
        }
        
        // 遍历所有已找到的素数
        for (int j = 0; j < cnt; j++) {
            // 只筛选小于等于n的数
            if (i * prime[j] > n) break;  // 如果i * prime[j]大于n,停止循环
            
            vis[i * prime[j]] = 1;  // 用i的最小质因数筛去i的倍数
            
            // 如果i能被当前的素数prime[j]整除
            if (i % prime[j] == 0) break; // 结束内层循环,确保筛选的质因数是最小的
        }
    }
    
    return cnt;  // 返回素数的个数
}

int main() {
    int n;
    cin >> n;  // 输入n
    cout << euler_sieve(n) << endl;  // 输出小于等于n的素数个数
    return 0;
}

2.约数

约数的定义:约数是指能够整除一个整数的整数。换句话说,如果一个整数 a 能被另一个整数 b 整除,且没有余数,那么 b 就称为 a 的一个约数。

如果 n  mod  b  =0,则 b 是 n 的约数。

2.1试除法求约数

以下是带有详细注释的代码:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

void solve()
{
    int n;
    cin >> n;
    vector<int> res;

    // 遍历 1 到 n 的平方根,查找 n 的约数
    for(int i = 1; i <= n / i; i++)
    {
        if(n % i == 0)
        {
            res.push_back(i);
            if(n / i != i) // 避免重复添加
            {
                res.push_back(n / i);
            }
        }
    }

    sort(res.begin(), res.end()); // 对结果数组进行排序

    for(auto e : res)
    {
        cout << e << " "; // 输出约数
    }
    cout << endl;
}

int main()
{
    int t;
    cin >> t; // 读取测试用例的数量
    while(t--)
    {
        solve();
    }
    return 0;
}

2.2 约数的个数

#include <iostream>
#include <unordered_map>

using namespace std;

typedef long long LL;

const int N = 110, mod = 1e9 + 7;

int main() {
    int n;
    cin >> n;  // 读取数字的数量

    unordered_map<int, int> primes;  // 哈希表存储素数及其出现次数

    while (n--) {
        int x;
        cin >> x;  // 读取每个数字

        // 素数分解
        for (int i = 2; i <= x / i; i++) {
            while (x % i == 0) {
                x /= i;        // 除以素数 i
                primes[i]++;   // 记录素数 i 的出现次数
            }
        }

        if (x > 1) primes[x]++;  // 如果 x 是素数,则记录
    }

    LL res = 1;  // 初始化结果
    // 计算约数个数
    for (auto p : primes) 
        res = res * (p.second + 1) % mod;  // 根据公式计算约数个数并取模

    cout << res << endl;  // 输出结果

    return 0;  // 程序正常结束
}

2.3约数之和

代码实现  + 详细注释

#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <vector>

using namespace std;

typedef long long LL;  // 定义长整型别名

const int N = 110, mod = 1e9 + 7;  // 常量 N 和模数 mod

int main()
{
    int n;
    cin >> n;  // 读取要处理的数字的个数

    unordered_map<int, int> primes;  // 存储素因数及其对应的次数

    while (n -- )  // 对每个数字进行处理
    {
        int x;
        cin >> x;  // 读取数字 x

        // 进行素因数分解
        for (int i = 2; i <= x / i; i ++ )  // 遍历从 2 到 sqrt(x)
            while (x % i == 0)  // 如果 i 是 x 的因数
            {
                x /= i;  // 将 x 除以 i
                primes[i] ++ ;  // 记录素因数 i 的次数
            }

        // 如果 x 大于 1,说明 x 本身是一个素数
        if (x > 1) primes[x] ++ ;  // 将素数 x 也加入到 primes 中
    }

    LL res = 1;  // 初始化结果为 1
    for (auto p : primes)  // 遍历所有的素因数及其次数
    {
        LL a = p.first, b = p.second;  // a 为素因数,b 为该素因数的指数
        LL t = 1;  // 初始化每个因数的约数和为 1
        while (b -- )  // 对于每个素因数的指数
            t = (t * a + 1) % mod;  // 计算 (1 + a + a^2 + ... + a^b) 的值

        res = res * t % mod;  // 将当前素因数的约数和与结果相乘,并对 mod 取模
    }

    cout << res << endl;  // 输出最终结果

    return 0;
}

2.4.最大公约数(GCD)

整除的定义::

1.GCD的定义:

#include<iostream>
using namespace std;
int gcd(int a , int b)
{
    return b ? gcd(b , a % b) : a;
}
int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        int a , b;
        cin >> a >> b;
        cout << gcd(a , b) << endl;
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/899770.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis 命令集 (超级详细)

目录 Redis 常用命令集 string类型 hash类型 list类型 set类型 zset类型 bitmap 类型 geo 类型 GEOADD (添加地理位置的坐标) GEOPOS (获取地理位置的坐标) GEODIST (计算两个位置之间的距离) GEOHASH (返回一个或多个位置对象的 geohash 值) GEORADIUS (根据用户…

DAF-Net:一种基于域自适应的双分支特征分解融合网络用于红外和可见光图像融合

题目&#xff1a;DAF-Net: A Dual-Branch Feature Decomposition Fusion Network with Domain Adaptive for Infrared and Visible Image Fusion 作者&#xff1a;JianXu发表时间&#xff1a;2024年9月 面临的问题&#xff1a;红外图像擅长捕捉热辐射&#xff0c;特别是在低…

国家能源集团携手海康威视研发攻克融合光谱煤质快检技术

10月24日&#xff0c;在国家能源集团准能集团黑岱沟露天煤矿&#xff0c;安装于准能选煤厂785商品煤胶带机中部的煤质快检核心设备&#xff0c;正在对当天装车外运的商品煤煤质进行实时检测。仅两分钟后&#xff0c;涵盖发热量、水分、灰分、硫分等多项指标的数据信息已传输到到…

前端方案:播放的视频加水印或者文字最佳实践

前言&#xff1a; 很多时候&#xff0c;视频的转码工作在后端&#xff0c;我们前端是拿到可以播放的链接进行播放即可。但是总是会出现一些定制化的需求&#xff0c;比如在视频的某个区域贴上水印、标识或者文字。这个时候大部分是由前端来操作的。 直接去修改播放器里的东西…

c语言指针详解2

c语言指针详解2 1.数组名理解 数组名其实是地址&#xff0c;是数组首元素的地址&#xff08;详解1有提及&#xff09; 我们可以根据打印来确认 我们发现数组名和数组⾸元素的地址打印出的结果⼀模⼀样&#xff0c;数组名就是数组⾸元素(第⼀个元素)的地址。 但是上述结论有…

DataX简介及使用

目录 一、DataX离线同步工具DataX3.0介绍 1.1、 DataX 3.0概览 1.2、特征 1.3、DataX3.0框架设计 1.4、支持的数据元 1.5、DataX3.0核心架构 1.6、DataX 3.0六大核心优势 1.6.1、可靠的数据质量监控 1.6.2、丰富的数据转换功能 1.6.3、精准的速度控制 1.6.4、强劲的…

轻松清理 PC 微信文件,释放存储空间

软件介绍 微信在我们的日常生活中使用频率极高&#xff0c;但随着时间的推移&#xff0c;它占用的存储空间也越来越大。以一个使用了两年时间的微信为例&#xff0c;它可能会占用多达几十G的存储空间。其中大部分都是与自己无关的各大群聊中的文件、视频、图片等内容&#xff…

java导出带图形的word

先看效果图&#xff1a;方法都是一样的&#xff0c;所以数据只做了前两组 第一步需要准备模版&#xff1a; 新建一个word插入图表&#xff0c;选择想要的图表。 编辑图表&#xff1a;营业额表示数字&#xff0c;季度表示文字。其他的样式编辑可根据自己的需求更改&#xff0c;…

从 Vue 2 到 Vue 3:全面升级指南

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Vue篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Vuet篇专栏内容:Vue-从 Vue 2 到 Vue 3&#xff1a;全面升级指南 前言 随着前端技术的不断发展&#xff0c;Vue.j…

基于大型语言模型的智能网页抓取

Google Gemini 是 Google AI 创建的大型语言模型 (LLM) 系列&#xff0c;可提供最先进的 AI 功能。Gemini 模型包括&#xff1a; Gemini Ultra — 最大、最强大的模型&#xff0c;擅长处理编码、逻辑推理和创意协作等复杂任务。可通过 Gemini Advanced&#xff08;原名 Bard&a…

FreeRTOS任务状态_改进播放控制 任务管理与调度 空闲任务及其钩子函数 两个Delay函数

任务状态_改进播放控制 FreeRTOS源码概述&#xff08;内存管理&#xff0c;入口函数&#xff0c;数据类型和编程规范&#xff09;创建任务&#xff08;声光色影&#xff0c;使用任务参数&#xff09;删除任务&#xff08;使用遥控器控制音乐&#xff09;-CSDN博客https://blog…

网络信息安全工程师证2024年如何报考?了解这几点让你轻松考证!收藏这一篇就够了

网络信息安全工程师是一种专门从事网络安全工作的职业。随着互联网的快速发展和普及&#xff0c;网络安全问题也日益突出&#xff0c;因此网络信息安全工程师的需求也越来越大。 网络信息安全工程师主要负责保护网络系统和数据的安全&#xff0c;防止黑客攻击、病毒侵入、数据泄…

2.3 塑性力学—等效应力

个人专栏—塑性力学 1.1 塑性力学基本概念 塑性力学基本概念 1.2 弹塑性材料的三杆桁架分析 弹塑性材料的三杆桁架分析 1.3 加载路径对桁架的影响 加载路径对桁架的影响 2.1 塑性力学——应力分析基本概念 应力分析基本概念 2.2 塑性力学——主应力、主方向、不变量 主应力、主…

qt生成uuid,转成int。ai回答亲测可以

// 生成一个随机的UUID QUuid uuid QUuid::createUuid(); // 将UUID转换为字符串 QString uuidStr uuid.toString(QUuid::WithoutBraces);// 计算MD5哈希值 QByteArray hash QCryptographicHash::hash(uuidStr.toUtf8(), QCryptographicHash::Md5);// 提取前8个字节并转换为…

设计模式——装饰者模式(8)

一、定义 指在不改变现有对象结构的情况下&#xff0c;动态地给该对象增加一些职责&#xff08;即增加其额外功能&#xff09;的模式。我们先来看一个快餐店的例子。快餐店有炒面、炒饭这些快餐&#xff0c;可以额外附加鸡蛋、火腿、培根这些配菜&#xff0c;当然加配菜需要额…

高翔【自动驾驶与机器人中的SLAM技术】学习笔记(十二)拓展图优化库g2o(一)框架

【转载】理解图优化&#xff0c;一步步带你看懂g2o框架 文章来源&#xff1a;理解图优化&#xff0c;一步步带你看懂g2o框架 小白&#xff1a;师兄师兄&#xff0c;最近我在看SLAM的优化算法&#xff0c;有种方法叫“图优化”&#xff0c;以前学习算法的时候还有一个优化方法…

BigFoot BigDebuffs

BigFoot BigDebuffs 大脚插件调整目标DOT图标大小&#xff0c;其目标就是让我们自己的DOT图标大一些&#xff0c;而团队其他人小一点&#xff0c;区别开。 178新版魔兽插件站-大脚插件站-178.com BigDebuffs-v41.zip 2024.10.24下载的版本 解压文件后&#xff0c;得到一堆的…

算法魅力-双指针之滑动窗口的叛逆

#1024程序员节#征文 目录 1.滑动窗口的定义 2.算法实战 2.1 长度最小的子数组 算法思路 2.2 无重复字符的最长子串 算法思路 2.3 最大连续 1 的个数 III 算法思路 哈希表的简要补充 结束语 祝大家1024程序节快乐&#xff01;&#xff01;&#xff01; 1.滑动窗口的定…

操作系统笔记(二)进程,系统调用,I/O设备

什么是进程? 一个正在执行的程序一个包含运行一个程序所需要的所有信息的容器进程的信息保存在一个进程表中( Process Table)。进程表中的每一项对应一个进程,称为进程控制块(Process control block,PCB)。 PCB信息包括: 用户ID(UID)、进程ID(PID)…

【开源免费】基于SpringBoot+Vue.JS在线视频教育平台(JAVA毕业设计)

本文项目编号 T 027 &#xff0c;文末自助获取源码 \color{red}{T027&#xff0c;文末自助获取源码} T027&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 新…