数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

这篇具有很好参考价值的文章主要介绍了数论 --- 约数和定理公式推导、最大公约数、欧几里得算法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

试除法求约数

和<试除法判断一个数是不是质数>是一个道理

从小到大枚举所有的约数,如果当前数能整除这个数的话,说明这个数就是当前数的约数

优化,与<试除法判断质数>是一样的

如果 d 是 n 的约数,n / d 也一定能整除 n,一个数的约数也一定是成对出现的,在枚举的时候也可以只枚举较小的那个约数,较大的那个约数可以直接计算,只需要枚举到 d ≤ n / d,d ≤  √ n 就可以了

时间复杂度为 O( n × √ a  ),100 × ( √ 2 × 10^9 )

4 w^2 = 1.6 × 10^9 2 × 10^9 5w^2 = 2.5 × 10^9

4 w √ 2 × 10^9 5w

√ 2 × 10^9 介于 4w 到 5w 之间,整个算法的时间复杂度在 400w 到 500w 之间

数论 --- 朴素筛法、埃氏筛法、线性筛法

数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

#include <iostream>
#include <algorithm>
//用 vector 存储一个数的所有约数
#include <vector>

using namesapce std;

//试除法求 n 的所有约数
vector<int> get_divisors(int n)
{
    //答案数组
    vector<int> res;
    //从小到大枚举 n 的所有约数 但是只枚举每一对约数里面较小的那个
    for(int i = 1;i <= n / i;i++ )
        //如果 n % i == 0,i 一定是 n 的约数 
        if(n % i == 0)
        {
            res.push_back(i);
            //n / i 也是约数,但是需要判断边界情况:有可能 n 是 i 的平方,两个约数一样,但是输出的时候不能重复
            if(i != n / i) res.push_back(n / i); 
        }
    //给约数排序
    sort(res.begin(),res.end());
    return res;
}

int main()
{
    int n;
    cin >> n;

    while(n-- ) 
    {
        int x;
        cin >> x;
        //求所有的约数
        auto res = get_divisors(x);
        //遍历然后输出
        for(auto t : res) cout << t << ' ';
        cout << endl;         
    }
    return 0;
}

求一个数的所有约数个数、所有约数之和 

基于算术基本定理,对于一个整数 N 分解质因数的结果为 p1^α1 * p2^α2 * . . . * pk^αk
约数个数:(α1 + 1) * (α2 + 1) * . . .  * (αk + 1),N 的约数个数和选法个数是一样的,乘法原理
约数之和:(p1^0 + p1^1 + . . . + p1^α1) * . . .  * (pk^0 + pk^1 + . . . + pk^αk)

int 范围内约数个数最多的一个数最多有 1500 个约数

时间复杂度为 O( n )

数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

给定 n 个整数 a1 ~ an,要求统计所有数乘积 a1 × a2 × . . . × an 的约数个数,先求 a1 ~ an 每一个数分解质因数的结果,然后把每一个数的指数累加在一起就可以了,从 a1 开始分解,一直分解到 an,假设求出来 a1 的某一个质因子 pi 的指数是 αi,可以用一个哈希表或者 map 把它存储下来,把每一项都分解完之后,map 中存储了整个乘积的因式分解的底数和指数,最终约数个数就是所有指数加 1 再相乘

数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

#include <iostream>
#include <algorithm>
// 这里选择使用哈希表
#include <unordered_map>

using namesapce std;

typedef long long LL;
const int mod = 1e9 + 7; 

int main()
{
    int n;
    cin >> n;
    // 定义哈希表存储所有底数和指数
    unordered_map<int,int> primes;
    while(n --)
    {
        int x;
        // 读入 x 然后把 x 分解
        cin >> x;
        // 从 2 开始枚举 分别分解每一个数,首先对于 a1 来说,把 a1 的所有质因子的次数找出来然后累加就可以了
        for(int i = 2;i <= x / i;i++ )
            while(x % i == 0)
            {
                x /= i;
                // i 的质因数的指数 + 1 最终 primes 里面存储了所有质因数的指数
                primes[i] ++;
            }
        //特判 x > 1 说明 x 是一个比较大的质因数 把剩下这个质因数加上就可以了
        if(x > 1) primes[x] ++;
    }
    LL res = 1;
    // 枚举所有质因数 答案就是所有的指数 + 1 再相乘
    for(auto prime : primes) res = res * (prime.second + 1) % mod;

    cout << res << endl;
    return 0;
}

只要能求出一个数质因数分解的结果,就可以分别求出约数个数和约数之和

求约数之和:也需要先分解质因数,然后直接带入求和公式就可以了

数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

#include <iostream>
#include <algorithm>
// 这里选择使用哈希表
#include <unordered_map>

using namesapce std;

typedef long long LL;
const int mod = 1e9 + 7; 

int main()
{
    int n;
    cin >> n;
    // 定义哈希表存储所有底数和指数
    unordered_map<int,int> primes;
    while(n --)
    {
        int x;
        // 读入 x 然后把 x 分解
        cin >> x;
        // 从 2 开始枚举 分别分解每一个数,首先对于 a1 来说,把 a1 的所有质因子的次数找出来然后累加就可以了
        for(int i = 2;i <= x / i;i++ )
            while(x % i == 0)
            {
                x /= i;
                // i 的质因数的指数 + 1 最终 primes 里面存储了所有质因数的指数
                primes[i] ++;
            }
        //特判 x > 1 说明 x 是一个比较大的质因数 把剩下这个质因数加上就可以了
        if(x > 1) primes[x] ++;
    }
    LL res = 1;
    // 枚举所有质因数 答案就是所有的指数 + 1 再相乘
    for(auto prime : primes) 
    {
        //先枚举每一个质数 p表示这个质数的底数 a表示这个质数的指数
        int  p = prime.first,a = prime.second;
        //需要求出来 p^0 + p^1 + ... + p^a
        //用 t 来表示总和,t 从 1 开始
        LL t = 1;
        //执行 a 次 t * p + 1 就可以得到 p^0 + p^1 + ... + p^a
        while(a -- ) t = (t * p + 1) % mod;
        res = res * t % mod;
    }
    cout << res << endl;
    return 0;
}

公式推导:约数和定理,约数个数定理  

数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

怎么求一个数的约数呢?

利用短除法对 72 进行分解质因数得到 72 = 2^3 × 3^2,2 是质数,3 是质数,2 与 3 都是 72 的质因数

为什么要对 72 进行分解质因数呢?

因为 72 这个合数的任意一个约数,都可以表示成 2^x 3^y

无论多大的数只要能够分解质因数,都能够把它的约数造出来

数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

接下来求 360 的正约数,我们通过短除法把它的正约数造出来,有多少种造法就有多少个正约数

数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

利用原材料 2,可以取零个 2、一个 2、两个 2、三个 2,一共有 4 种方法

利用原材料 3,一共有 3 种方法

利用原材料 5,一共有 2 种方法

把每个质因数上的指数 + 1 再相乘,就得到某一个数的正约数的个数

数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

接下来求所有正约数之和,首先如果要把 360 的正约数全部穷举出来就是一个不小的工程,还需要求和,工程较大,容易出错,因此我们还是用造的思想把约数给造出来

我们可以利用分类讨论的思想,以 2 为原材料可以造出 2^0、2^1、2^2、2^3,以 2 和 3 为原材料,以此类推

第一类方案与第二类方案的总数之和如下

数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

利用 2、3、5 与 利用 2、5 来造 360 的约数,可以发现 2、3 已经造好了,只需要乘上一个 5 就可以了

在利用 2、3、5 造约数的过程中,已经把 3、5 的情况包括在内: 2^0 × 3^1、2^0 × 3^2

得到最终所有正约数的总和就是 ( 2^0 + 2^1 + 2^2 + 2^3) × (3^0 + 3^1 + 3^2) × (1 + 5^1)

 数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

不穷举,采用提取公因式的方式,先得到 2 和 3 参与的,后得到 2、3、5 参与的

 数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

 数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

欧几里得算法 / 辗转相除法

数论中的基本性质:

如果 d 能整除 a,并且 d 能整除 b,d 就能整除 a + b,也能整除 a 的若干倍 + b 的若干倍

数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

辗转相除法的核心原理:

利用这个性质,a 和 b 的最大公约数等于 b 和 a mod b 的最大公约数

 数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

怎么证明左右两边的最大公约数是相同的呢?

a 和 b 的最大公约数等于 b 和 a - c × b 的最大公约数

数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

证明可以利用如下性质

对于左边的任何一个公约数 d 能整除 a,d 能整除 b,所以 d 能整除 b,所以 d 能整除 a - c × b,所以左边的任何一个公约数都是右边的一个公约数

 数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

证明右边的任何一个公约数也是左边的一个公约数

d 能整除 b,d 能整除 a - c × b,所以 d 能整除 b,只需要证明 d 能整除 a 就可以了

d 能整除 a - c × b,所以 d 能整除 a - c × b × 1 + b × c,抵消后 d 能整除 a,所以右边任何一个公约数都是左边的一个公约数

数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

同样左边任何一个公约数都是右边的一个公约数,所以这两个公约数的集合相同的,最终得证左边的最大公约数等于右边的最大公约数,所以可以直接用性质来计算最大公约数

最大公约数

数论 --- 约数和定理公式推导、最大公约数、欧几里得算法

给出 n 组 a、b,求每一组的最大公约数,时间复杂度 O( logn )文章来源地址https://www.toymoban.com/news/detail-401143.html

#include <iostream>

using namespace std;
// 返回 a 和 b 的最大公约数
int gcd(int a,int b) 
{
    
    // 如果 b 不是 0,返回 gcd(b,a % b),当 b 等于 0 的时候,a 和 0 的最大公约数一定是 a,因为 0 可以整除任何数
    return b ? gcd(b,a % b) : a;
}

int main()
{
    int n;
    scanf("%d",&n);
    while(n-- )
    {
        int a,b;
        //每次读入两个数
        scanf("%d%d",&a,&b);
        //返回 a 和 b 的最大公约数
        printf("%d\n",gcd(a,b));
    }
    return 0;
}

到了这里,关于数论 --- 约数和定理公式推导、最大公约数、欧几里得算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 最大公约数和最小公倍数问题

    等差数列 蓝桥杯192 gcd问题 题目描述 数学老师给小明出了一道等差数列求和的题目。但是粗心的小明忘记了一 部分的数列,只记得其中 N 个整数。 现在给出这 N 个整数,小明想知道包含这 N 个整数的最短的等差数列有几项? 思路:求出每一项之差的最大公约数,以这个

    2023年04月09日
    浏览(30)
  • 【算法】辗转相除法求最大公约数

    辗转相除法 ,又称 欧几里德算法(Euclidean Algorithm) ,是求两个数的 最大公约数(greatest common divisor) 的一种方法。用较大的数除以较小的数,再以除数和余数反复做除法运算,当余数为0时,取当前算式除数为最大公约数。 求30和18的最大公约数: 30 /  18  = 1 余  12 18 

    2024年02月14日
    浏览(41)
  • C++ 最大公约数与最小公倍数

    (一)简单的两个正整数  求 最大公约数 (引入专题) 思路: 根据 “欧几里得算法”  ,即 “辗转相除法” 原理如下: 题意: 求出   a  , b  两个正整数的最大公约数 设  k = a / b,   r = a % b 即    a = k * b + r 又设  d  为 a 和 b 的一个公约数 那么由  r = a - k * b,  可

    2024年02月06日
    浏览(32)
  • 辗转相除法——求最大公约数(易懂详解)

    定义 最大公因数:也称最大公约数、最大公因子,指两个或多个整数共有约数中最大的一个。 辗转相除法:欧几里得算法又称辗转相除法,是指用于计算两个非负整数a,b的最大公约数。应用领域有数学和计算机两个方面。计算公式gcd(a,b) = gcd(b,a mod b)。 举例理解 比如现在要

    2024年02月16日
    浏览(30)
  • 【ARM汇编】如何用汇编求最大公约数?

    CSDN话题挑战赛第1期 活动详情地址 :话题PK赛 参赛话题 :汇编知识分享 话题描述 :我们的计算机知识就像一座金字塔,底层是数学,上面是数字电路,然后是汇编,再往上是操作系统、网络、数据库、高级编程语言、框架等等…我们不可能精通这个金子塔的每一层, 但是

    2024年01月25日
    浏览(32)
  • C语言—最大公约数和最小公倍数

    作者主页: paper jie的博客_CSDN博客-C语言,算法详解领域博主 本文作者: 大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。 本文录入于 《算法详解》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将算法基础知识一网打尽,希望

    2024年02月13日
    浏览(26)
  • P1029 最大公约数和最小公倍数问题

    3 2 1 上题目链接: P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题 本小蒟蒻的原始思路就是枚举所有范围内的数,分别求出他们的最大公约数和最小公倍数,再看是否满足题意。 于是就有了以下一言难尽的东西(;′⌒`)↓ 皇天不负有心人,收到了2个TLE,其他全WA 自我反

    2024年02月19日
    浏览(25)
  • 【Python 随练】求最大公约数和最小公倍数

    输入两个正整数 m 和 n,求其最大公约数和最小公倍数。 在本篇博客中,我们将解决一个常见的数学问题:求两个正整数的最大公约数和最小公倍数。我们将提供问题的解析,并给出一个完整的代码示例来计算最大公约数和最小公倍数。 给定两个正整数m和n,我们需要求它们

    2024年02月09日
    浏览(56)
  • 【C语言】求最大公约数和最小公倍数

    方法一:利用 定义法 求最大公因数和最小公倍数 方法二:最小公倍数求法同上, 最大公约数方法不同 方法一方法二的结果示例如下   方法三:利用 辗转相除法 求最大公约数和最小公倍数 法(1)结果示例如下:  法(2)示例结果如下:  以上就是用C语言循环和循环之前的

    2024年02月07日
    浏览(33)
  • 最大公约数的三种求法——(C语言)

    如何求解最大公约数,首先了解什么是最大公约数, 如果有一个自然数a能被自然数b整除,则称a为b的倍数,b为a的约数。几个自然数公有的约数,叫做这几个自然数的公约数。公约数中最大的一个公约数,称为这几个自然数的最大公约数。 例: 在2、4、6中,2就是2,4,6的最

    2024年02月02日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包