数论(四)——欧拉函数

目录

  • 欧拉函数
  • 用公式求欧拉函数
  • 筛法求欧拉函数
  • 欧拉定理

欧拉函数

定义
在数论中,对正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目。

1.φ(1)=1
2.互质是公约数只有1的两个整数,叫做互质整数。
公式
n 分解质因数后:n=p1a1 × p2a2 × p3a3 … pkak,(其中 pi 为质数)
那么 φ(n) = n × (1 - 1/p1) × (1 - 1/p2) ×… ×(1 - 1/pk)
公式证明
思路:
1.从1—n中去掉p1,p2…pk的的倍数;
2.加上所有pi × pk 的倍数(上一步会重复删除既是pi又时pk的倍数,所以这一步要加回来,这是容斥原理的思想)
3.减去所有 pi × pj × pk 的倍数 (容斥原理)
N - N/p1 - N/p2 - … N/pk + N/p1p2 + N/p1p3 + …+ … - N/p1p2p3 - N/p1p2p4 - … 按照这个规律(N - 所有 N/一个质数 + 所有N/两个质数乘积 - 所有N/三个质数乘积 + 所有N/四个质数乘积 - … + …)
我们通过容斥原理推到出的上面的式子合并以后就是上面给出的求欧拉函数的公式(红字)

用公式求欧拉函数

时间复杂度:瓶颈在于分解质因数,而分解质因数的时间复杂度时O(sqrt(n)),因此用公式求欧拉函数的时间复杂度也是O(sqrt(n)).

给定 n 个正整数 ai,请你求出每个数的欧拉函数。
思路很简单,就是先分解质因数,然后代入欧拉函数公式即可,关于分解质因数的方法,可以参照我前面的博客 点这!

#include

using namespace std;

int main()
{
    int n;
    cin >> n;
    
    while(n -- )
    {
        int a;
        cin >> a;
        
        int res = a;
        for(int i = 2; i <= a/i; i ++ )
        {
            if(a % i == 0)
            {
                res = res / i * (i - 1);
                while(a % i == 0) a /= i;
            }
        }
        if(a > 1) res = res / a * (a - 1); //a>1说明a有大于sqrt(a)的质因子
        
        cout << res << endl;
    }
    return 0;
}


res = res/i × (i - 1) 与 res = res × (1 - 1/i)在数学上是等价的,但是为了防止出现小数,我们要写成前面的形式,因为1/i 是小数,会有精度问题。

筛法求欧拉函数

在学习筛法求欧拉函数之前,一定要先看一下什么是欧拉筛(线性筛),点这!

给定一个正整数 n,求 1∼n 中每个数的欧拉函数之和。

#include
#include

using namespace std;

typedef long long LL;

const int N = 1e6 + 10;
int primes[N],cnt; //primes 存质数 
int phi[N]; //phi 存欧拉函数
bool st[N]; //st[i]存 i 是否为质数 

LL get_eulers(int n)
{
    phi[1] = 1; //从定义出发,规定φ(1) = 1
    for(int i = 2; i <= n; i ++ )
    {
        if(!st[i])
        {
            primes[cnt ++ ] = i;
            phi[i] = i - 1; // 1)
        }
        for(int j = 0; primes[j] <= n/i; j ++ )
        {
            st[primes[j] * i] = true;
            if(i % primes[j] == 0)  // 2)
            {
                phi[primes[j] * i] = phi[i] * primes[j];
                break;
            }
            phi[primes[j] * i] = phi[i] * (primes[j] - 1); //3)
        }
    }
    
    LL res = 0;
    for(int i = 1; i <= n; i ++ ) res += phi[i];
    return res;
}

int main()
{
    int n;
    cin >> n;
    cout << get_eulers(n) << endl;
    return 0;
}

时间复杂度为O(n)
:筛法求欧拉函数,思路与欧拉筛基本一致,不同处在于注释中的1)2)3),下面分别对这三处做出了解释:
1)phi[i] = i - 1:如果一个数 i 是质数,那么根据欧拉函数的定义,1~i-1都与 i 互质,所以 phi[i] = i - 1;
2)i mod primes[j] = 0时,φ(pj×i)是多少?(Pj×i 的欧拉函数是多少)<为了方便,用pj表示 primes[j]>
i mod pj = 0,说明 pj是 i 的一个质因子,根据欧拉函数φ(i)= i × (1 - 1/p1) × (1 - 1/p2) … (1 - 1/pj) … (1 - 1/pk),也就是说,在求φ(i)的过程中,已经乘过了一个(1-1/pj
易知,pj 也是pj × i 的质因子,也就是,pj × i 相对于 i 只是多一个了 pj 这个质因子而已,所以φ(pj × i)= pj × i × (1 - 1/p1) × (1 - 1/p2) … (1 - 1/pj) … (1 - 1/pk)。
根据 φ(i) 和 φ(pj × i) 可得,phi[pj × i] = phi[i] × pj
3)i%primes[j] != 0 时,pj一定是pj× i 的一个最小质因子,而且pj是不包含在 i 的质因子当中的,因此,假设 i 的所有质因子是 p1 — pk,φ(i) = i × (1 - 1/p1) ×…×(1 - 1/pk),由于 pj× i 的所有质因子是 比 i 的所有质因子多了一个 pj,其余完全一样,所以有 φ(pj × i)= pj × i × (1 - 1/p1) × (1 - 1/p2) × . . .× (1 - 1/pk) × (1 - 1/pj),可得phi[pj * i] = phi[i] * (pj-1)

欧拉定理

欧拉定理内容
若a,m互质,则有如下性质
数论(四)——欧拉函数_第1张图片
特例:当m是质数时
aφ(m) = am-1≡ 1 (mod m),这一特例被称为费马定理
举个“栗子”
a = 5,m = 6
则 5φ(6) mod 6 = 5 2mod 6 = 25 mod 6 ≡ 1

“≡”是数论中表示同余的符号。即给定一个正整数n,如果两个整数a和b满足a-b能被n整除,即(a-b) mod n = 0,那么就称整数a与b对模n同余,记作a≡b(modn),同时可成立amodn=b。

你可能感兴趣的:(#,数学知识,算法,欧拉公式,欧拉函数)