欧拉函数章-数论代码笔记(超级细节)

前情提示:如果不了解分解质因数算法和欧拉筛质数的算法,强烈建议先看看我之前的文章 质数章-数论代码笔记(超级细节)。否则可能会比较难理解。

在介绍欧拉函数之前,我想给大家一个初始印象,把欧拉函数当成一个类似于“质数”的定义,同样的,类似于质数,我们有判断一个数是不是质数,筛一个范围内的质数的方法,我们也有判断一个 数是不是欧拉函数,计算一个范围内的欧拉函数的方法。

好了,让我们进入正题。

1. 欧拉函数

首先给出欧拉函数的定义:

如果为了方便,可以直接记忆然后去看欧拉函数筛,如果想更进一步了解,且听我分析分析。

我们想直接求与N互质的数比较难(调用gcd函数)。所以我想从反方向入手,先找出与N不是互质的数。由算数基本定理我们知道,一个整数一定能分解成质数的乘积。那么我们可以知道如果1~N中有一个数是这些质数的倍数,那么它一定不与N互质。

不妨以p_{1}为例,1~N中为p_{1}的倍数的个数,我们可以直接用\frac{N}{p_{1}}算出来,那么p_{2}, p_{3}....的倍数是\frac{N}{p_{i}}

直接把这些数相加吗?很显然不是,拿6举例子,它会被2,3给标记。所以我们要用到集合论中的容斥原理。

话说我对容斥原理的理解就是+,-,+,-

如果你对数学不感兴趣,请和我继续下去,我不会介绍容斥原理(虽然可以从韦恩图中推出来这个公式)

最后化简并提取我们能得到

你可能会比较奇怪,为什么要写成这个形式我写成(1 - \frac{1}{p_{i}})这样不行吗?

答案是,为了方便计算机计算。。。。。

下面看代码:

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;
}

首先是分解质因数(不会的自觉去找资料),然后边分解边累计结果。时间复杂度是分解质因数的时间复杂度,为O(\sqrt{a})

注意啊,有乘法有除法,先除后乘防止溢出,类似于有加法有减法,先减后加。

Tips: 第二种思路推公式:

首先有一点:

  • 欧拉函数是一个积性函数,如果m,n互质,那么\phi(mn) = \phi(m)\phi(n)。这个性质很重要啊,一会的欧拉函数筛也要用到这个性质。

我从网络上找了张图,很容易理解。

2. 欧拉函数筛

类似于质数,我们求出了一个数的欧拉函数,那有没有一种办法,我能求出1~N的欧拉函数呢。

有,就是使用欧拉函数筛。

先给出一个公式:

为什么会有这个公式?

首先我们知道当i 与 p(p是质数)互质时,就有 \phi(p) = p-1 ,由上面提到的欧拉函数的积性我们知道,\phi(ip) = \phi(p) \phi(i)= (p-1)\phi(i)

那当不互质的时候呢?我们有\phi(i)=i\times(1-\frac{1}{p_{1}})\times(1-\frac{1}{p_{2}})\times....\times(1-\frac{1}{p_{k}})已经包含了i*p的所有因子,所以\phi(ip)=ip\times(1-\frac{1}{p_{1}})\times(1-\frac{1}{p_{2}})\times....\times(1-\frac{1}{p_{k}}) = p \times \phi(i)

看代码,与线性筛框架基本一模一样。每次都用最小的质因子去计算出对应的欧拉函数。

如果i是质数,它会直接赋值为i-1,如果i是合数,在遍历到它之前,它就会被筛掉(计算出值)。

int primes[N], cnt;     // primes[]存储所有素数
int euler[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;
            euler[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)
            {
                euler[t] = euler[i] * primes[j];
                break;
            }
            euler[t] = euler[i] * (primes[j] - 1);
        }
    }
}

  • 21
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 欧拉函数也称为欧拉-费马函数或费马函数,用符号φ(n)表示,表示小于等于n且与n互质的正整数的个数。 以下是一个用MATLAB编写的求欧拉函数代码示例: ```matlab function result = euler_function(n) result = n; % 初始化结果为n p = 2; % 设置初始的素数为2 % 计算欧拉函数 while p^2 <= n if mod(n, p) == 0 result = result * (1 - 1 / p); while mod(n,p) == 0 n = n / p; end end p = p + 1; end % 处理剩余的质因数 if n > 1 result = result * (1 - 1 / n); end end ``` 使用方法: ```matlab n = 12; % 输入要求解欧拉函数的数n result = euler_function(n); % 调用欧拉函数的方法 disp(result); % 输出结果 ``` 这个代码通过迭代计算n的所有质因数,并根据欧拉函数的公式进行计算,最终得到欧拉函数的值。 ### 回答2: 欧拉函数(Euler's totient function)是一个计算小于等于给定正整数n的所有与n互质的正整数的个数。以下是用Matlab实现欧拉函数代码: ```matlab function euler = euler_function(n) euler = n; % 将结果初始化为n p = 2; % 从最小的素数2开始 while p * p <= n % 当p的平方大于n时结束循环 if mod(n, p) == 0 % 若n能整除p euler = euler - euler / p; % 将结果减去n除以p的值(贡献) while mod(n, p) == 0 % 如果n继续能整除p,则继续除以p n = n / p; end end p = p + 1; % 继续查找下一个素数 end if n > 1 % 若n不为1,则n是一个大于sqrt(n)的质数 euler = euler - euler / n; % 将结果减去n除以n的值(贡献) end end ``` 这个函数接受一个正整数n作为输入,并返回n的欧拉函数值。函数首先将结果初始化为n,然后从最小的素数2开始,一直遍历到sqrt(n)为止。如果n能被p整除,它将以p的贡献减少结果。然后继续查找下一个素数。最后,如果n不等于1,则n是一个大于sqrt(n)的质数,将其贡献减少结果。 希望以上的代码可以满足你的需求。 ### 回答3: 欧拉函数数论中一个重要的函数,用于计算小于n且与n互质的正整数的个数。欧拉函数的公式为:φ(n)=n×(1-1/p1)×(1-1/p2)×⋯×(1-1/pk)其中p1,p2,...,pk是n的所有质因数。 下面是求欧拉函数的MATLAB代码: ```matlab function result = euler_phi(n) result = n; for i = 2 : round(sqrt(n)) if (n % i == 0) result = result * (1 - 1/i); while (n % i == 0) n = n / i; end end end if (n > 1) result = result * (1 - 1/n); end end ``` 在这段代码中,我们首先将结果初始化为n。然后从2到sqrt(n)遍历,如果n能被i整除,则说明i是n的一个质因数。这时,我们将结果乘以(1-1/i),然后不断将n除以i直到n不能再被i整除为止。最后,如果n大于1,说明n本身也是一个质因数,我们将结果乘以(1-1/n)。 这段代码可以在MATLAB中调用,例如: ```matlab n = 12; result = euler_phi(n); disp(result); ``` 这样就可以得到12的欧拉函数值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值