算法基础系列第四章——数论之从欧拉卷到欧几里得(1)

简介: 算法基础系列第四章——数论之从欧拉卷到欧几里得(1)

欧拉函数


概念引入


1. 互质: 如果两个数的最大公约数是1,则称这两个数互质。

2. 欧拉函数: 在1~N中与N互质的数的个数被称为欧拉函数,记作:φ(N) 假如对这个正整数按照算术基本定理分解,就可按照下图的流程,推导出欧拉函数的计算公式

微信图片_20221018134452.png

公式法求欧拉函数


算法模板


实现流程图:

微信图片_20221018134602.png

算法的代码描述如下:

公式法求欧拉函数
int phi(int x)
{
    int res = x;
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0)
        {
            res = res / i * (i - 1);
            while (x % i == 0) x /= i;
        }
    if (x > 1) res = res / x * (x - 1);
    return res;
}

例题描述

微信图片_20221018134656.jpg

参考代码(C++版本)


疑难点剖析


一、分解质因数是基础

对分解质因数的算法模板要清楚,假如对分解质因数比较模糊的小伙伴可以看看这篇文章喔,也是挂过热榜的,值得信赖呀

二、欧拉函数的计算公式

记得住最好,假如记不住了,可以利用容斥原理,自己推理两三个数据就可以发现规律喔

让我好好想想


线性筛法求欧拉函数


公式法求欧拉函数适用于只求少量数据的欧拉值,倘若题目要求很多数据的欧拉值或者欧拉值的乘积、和。那么公式法就可能TLE,因此,借助线性筛法的模板来优化求公式法求欧拉值的过程。


算法模板


算法实现流程图:

微信图片_20221018134849.jpg算法模板代码实现:

筛法求欧拉函数
int primes[N], cnt;   // primes[]存储所有素数
int phi[N];     // 存储每个数的欧拉函数
bool st[N];     // st[x]存储x是否被筛掉
void get_eulers(int n)
{
    euler[1] = 1;
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i])
        {
            primes[cnt ++ ] = i;
            phi[i] = i - 1;
        }
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            int t = primes[j] * i;
            st[t] = true;
            if (i % primes[j] == 0)
            {
                phi[t] = phi[i] * primes[j];
                break;
            }
            phi[t] = phi[i] * (primes[j] - 1);
        }
    }
}

例题描述

微信图片_20221018134952.jpg

参考代码(C++版本)


疑难点剖析


一、线性筛法的难点在于如何结合公式统计出当前参数的欧拉值,将相应结果存放到phi数组中。


情况一:当前这个数据是质数。 与质数n互质的数的个数有n-1个。比如质数7。1~6与它的最大公约数都是1,互质的个数就是6。因此可以得到phi[n] = n-1;


情况二:筛选中,当前这个质数primes[j]是i的质因数 phi[primes[j] * i] 可变型为phi[primes[j] ] * phi[i] 。因为primes[j]是i的质因数,所以在用公式算phi[i]的时候就已经把(1-1/primes[j])算了。所以对于phi[primes[j]]就只用将剩下的primes[j]乘上。 因此 phi[primes[j] * i] = phi[i]*primes[j];


情况三:筛选中,当前这个质数primes[j]不是i的质因数。 因为primes[j]不是质因数了,就得独立的对它进行公式计算,即phi[ primes[j] ] = primes[j] x (1 - 1/primes[j]) x phi[i] 因此,结果为: phi[primes[j] * i] = phi[i]*(primes[j]-1);


二、注意范围,因为题目所给的数据就能很大,统计欧拉值的时候以乘积的形式统计的,可能会造成溢出。对于数论的题,可以泛泛而谈大多数时候都是要用long long 类型的,因为所给的数据一般比较大,比如2 x 10^9。假如再进行乘法运算,就会溢出


相关文章
|
4月前
【刷题记录】最大公因数,最小公倍数(辗转相除法、欧几里得算法)
【刷题记录】最大公因数,最小公倍数(辗转相除法、欧几里得算法)
|
7月前
|
算法 数据安全/隐私保护
什么是扩展欧几里得算法?
【5月更文挑战第13天】什么是扩展欧几里得算法?
119 3
|
6月前
|
算法 安全 数据挖掘
解锁编程之门:数论在算法与加密中的实用应用
解锁编程之门:数论在算法与加密中的实用应用
宝藏例题(欧几里得算法+素数的三种境界………)
宝藏例题(欧几里得算法+素数的三种境界………)
宝藏例题(欧几里得算法+素数的三种境界………)
|
7月前
|
算法 Python
Python欧几里得算法找最大公约数
Python欧几里得算法找最大公约数
82 0
|
7月前
|
算法 搜索推荐 程序员
C语言第二十二练——扩展欧几里得算法
C语言第二十二练——扩展欧几里得算法
72 0
P4057 [Code+#1]晨跑(数学分析,辗转相除法模板(欧几里得算法))
P4057 [Code+#1]晨跑(数学分析,辗转相除法模板(欧几里得算法))
71 0
|
算法 搜索推荐 程序员
欧几里得算法
欧几里得算法(Euclidean algorithm)是一种计算两个数的最大公约数(Greatest Common Divisor,简称 GCD)的算法。欧几里得算法的基本思想是通过辗转相除的方式,将两个数逐步缩小,直到它们的公约数为止。欧几里得算法的时间复杂度为 O(log n)。
240 1
|
算法 Java
欧几里得算法(GCD, 辗转相除法)
欧几里得算法(GCD, 辗转相除法)
|
算法 Java C++
秒懂算法 │数论之GCD和LCM
本篇内容介绍了GCD和LCM的多种编码方法及其典型例题。
2086 0
秒懂算法 │数论之GCD和LCM