欧拉函数

欧拉函数

1. 欧拉函数原理

欧拉函数

  • 1 ~ N 中与 N 互质的数的个数被称为欧拉函数,记为 ϕ ( N ) \phi(N) ϕ(N),例如 ϕ ( 6 ) = 2 \phi(6)=2 ϕ(6)=2,因为1~6中和6互质的有1和5。

  • 特殊规定 ϕ ( 1 ) = 1 \phi(1)=1 ϕ(1)=1

  • 如果一个数N可以质因数分解为 p 1 α 1 ∗ p 2 α 2 ∗ . . . ∗ p k α k p_1^{\alpha_1}*p_2^{\alpha_2}*...*p_k^{\alpha_k} p1α1p2α2...pkαk ,则
    ϕ ( N ) = N ∗ p 1 − 1 p 1 ∗ p 2 − 1 p 2 ∗ . . . ∗ ∗ p k − 1 p k \phi(N) = N*{\frac{p_1-1}{p_1}}*{\frac{p_2-1}{p_2}}*...**{\frac{p_k-1}{p_k}} ϕ(N)=Np1p11p2p21...pkpk1

  • 使用容斥原理可以证明上述结论:

    (1)减去所有在1~N之间的是 p 1 , p 2 , . . . , p k p_1,p_2,...,p_k p1,p2,...,pk 倍数的数据的个数

    (2)加上所有在1~N之间的是 p 1 , p 2 , . . . , p k p_1,p_2,...,p_k p1,p2,...,pk 任意两个数据之积倍数的数据的个数

    (3)减去所有在1~N之间的是 p 1 , p 2 , . . . , p k p_1,p_2,...,p_k p1,p2,...,pk 任意三个数据之积倍数的数据的个数

    (4)…

    即:
    N − N p 1 − N p 2 − . . . − − N p k + N p 1 p 2 + N p 1 p 3 + . . . + N p k − 1 p k − N p 1 p 2 p 3 − N p 1 p 2 p 4 − . . . − N p k − 2 p k − 1 p k . . . . . . N - \frac{N}{p_1} - \frac{N}{p_2} - ... - - \frac{N}{p_k} \\ +\frac{N}{p_1p_2} + \frac{N}{p_1p_3} + ... + \frac{N}{p_{k-1}p_k} \\ -\frac{N}{p_1p_2p_3} - \frac{N}{p_1p_2p_4} - ... - \frac{N}{p_{k-2}p_{k-1}p_k} \\\\ ...... Np1Np2N...pkN+p1p2N+p1p3N+...+pk1pkNp1p2p3Np1p2p4N...pk2pk1pkN......
    这个式子就是 ϕ ( N ) \phi(N) ϕ(N)

  • 该算法的瓶颈是在质因数分解,因此时间复杂度是 O ( N ) O(\sqrt N) O(N )的。


筛法求欧拉函数

  • 这里我们想要求解1~N中每个数据的欧拉函数值,如果一个一个求解的话,时间复杂度为 O ( N × N ) O(N \times \sqrt N) O(N×N ),很慢,因此这里可以使用筛法求解1~N中每个数据的欧拉函数,时间复杂度是 O ( N ) O(N) O(N)的。

  • 筛质数的线性筛法中加入一些操作,可以解决该问题。其实在线性筛法的过程中可以求出很多内容。

  • 具体步骤可以参考如下代码

const int N = 1000010;

int primes[N], cnt;  // 存储cnt个质数
int phi[N];  // 每个数的欧拉函数值
bool st[N];  // 是否被筛掉

// 时间复杂度:O(n)
void get_eulers(int n) {
    phi[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++) {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) {
                phi[primes[j] * i] = phi[i] * primes[j];
                break;
            }
            phi[primes[j] * i] = phi[i] * (primes[j] - 1);
        }
    }
}
  • 分析如下:
// 时间复杂度:O(n)
void get_eulers(int n) {
    phi[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!st[i]) {
            primes[cnt++] = i;
            phi[i] = i - 1;  // i为质数,1~i-1均与其互质
        }
        for (int j = 0; primes[j] <= n / i; j++) {
            // 令primes[j] = pj, 考察数据a = pj * i, b = i
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) {
                // 因为pj是a的质因数,根据欧拉公式,容易推出:phi[a] = phi[b] * pj;
                phi[primes[j] * i] = phi[i] * primes[j];
                break;
            }
            // 此时i % pj != 0
            // phi[a] = phi[b] * pj * (1 - 1/pj) = phi[b] * (pj - 1);
            phi[primes[j] * i] = phi[i] * (primes[j] - 1);
        }
    }
}

欧拉定理

  • 同余的性质

    (1)性质1:a≡a(mod m);(反身性)

    (2)性质2:若a≡b(mod m),那么b≡a(mod m);(对称性)。

    (3)性质3:若a≡b(mod m)b≡c(mod m),那么a≡c(mod m);(传递性)。

    (4)性质4:若a≡b(mod m)c≡d(mod m),那么a±c≡b±d(mod m);(可加减性)。

    (5)性质5:若a≡b(mod m)c≡d(mod m),那么ac≡bd(mod m);(可乘性)。

    (6)性质6:若a≡b(mod m),那么 a × n ≡ b × n ( m o d    m ) a \times n≡b \times n(mod \ \ m) a×nb×nmod  m,(其中n为自然数);

    (7)性质7:若 a × c ≡ b × c ( m o d    m ) , ( c , m ) = 1 a \times c≡b \times c(mod \ \ m),(c,m)=1 a×cb×cmod  m,cm=1,那么a≡b(mod m),(记号(c,m)表示c与m的最大公约数);

    (8)性质8:若a≡b(mod m),那么a的n次方和b的n次方也对于m同余;

    (9)性质9:若a≡b(mod m)、c≡d(mod m)、e≡f(mod m)……x≡y(mod m),那么:a+c+e+……+xb+d+f+……+y也对于m同余。

  • 欧拉定理:若a与n互质,则有: a ϕ ( n ) ≡ 1 ( m o d   n ) a^{\phi(n)} \equiv 1(mod \ n) aϕ(n)1(mod n)

    证明:1~n中和n互质的数有 ϕ ( n ) \phi(n) ϕ(n) 个,假设分别是: b 1 , b 2 , . . . , b ϕ ( n ) b_1,b_2,...,b_{\phi(n)} b1,b2,...,bϕ(n),因为a与n互质,则有: a ∗ b 1 , a ∗ b 2 , . . . , a ∗ b ϕ ( n ) a*b_1,a*b_2,...,a*b_{\phi(n)} ab1,ab2,...,abϕ(n) 均与n互质,并且两两互不相同(反证法,假设存在两个数在模n的前提下是相同的,假设是 a × b i ≡ a × b j ( m o d    n ) a \times b _ i ≡ a \times b _j (mod \ \ n) a×bia×bj(mod  n),则 a × ( b i − b j ) ≡ 0 ( m o d    n ) a \times (b_i - b_j)≡0 (mod \ \ n) a×(bibj)0(mod  n),所以 b i − b j ≡ 0 ( m o d    n ) b_i - b_j≡0 (mod \ \ n) bibj0(mod  n),此时推出 b i 、 b j b_i、b_j bibj相等,矛盾),所以这两组数是同一组数(在模n的前提下),只不过是位置调换了一下,因此这两组数的乘积同余,所以有:
    a ϕ ( n ) × ( b 1 b 2 . . . b ϕ ( n ) ) ≡ ( b 1 b 2 . . . b ϕ ( n ) ) ( m o d   n ) a^{\phi(n)}\times(b_1b_2...b_{\phi(n)}) \equiv (b_1b_2...b_{\phi(n)}) (mod \ n) aϕ(n)×(b1b2...bϕ(n))(b1b2...bϕ(n))(mod n)
    根据同余的性质,有: a ϕ ( n ) ≡ 1 ( m o d   n ) a^{\phi(n)} \equiv 1 (mod \ n) aϕ(n)1(mod n),证毕!

  • 欧拉定理的一个特例(费马小定理):若a与p互质,且p是质数,则有: a p − 1 ≡ 1 ( m o d   p ) a^{p-1} \equiv 1(mod \ p) ap11(mod p)

2. AcWing上的欧拉函数题目

AcWing 873. 欧拉函数

问题描述

分析

  • 从定义出发直接求解即可。

  • 计算量:主要在质因数分解上,质因数分解的计算量最多是 a i \sqrt {a_i} ai ,然后最多100个数,因此计算量在 100 × 2 × 1 0 9 ≈ 4 × 1 0 6 100 \times \sqrt {2 \times 10 ^ 9} \approx 4 \times 10 ^ 6 100×2×109 4×106,400多万的计算量,完全可以接受。

代码

  • C++
#include <iostream>

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);
        
        cout << res << endl;
    }
    
    return 0;
}

AcWing 874. 筛法求欧拉函数

问题描述

分析

  • 使用筛法求欧拉函数即可。

代码

  • C++
#include <iostream>

using namespace std;

typedef long long LL;

const int N = 1000010;

int primes[N], cnt;  // 存储cnt个质数
int phi[N];  // 每个数的欧拉函数值
bool st[N];  // 是否被筛掉

LL get_eulers(int n) {
    
    phi[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++) {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) {
                phi[primes[j] * i] = phi[i] * primes[j];
                break;
            }
            phi[primes[j] * i] = phi[i] * (primes[j] - 1);
        }
    }
    
    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;
}

AcWing 201. 可见的点

问题描述

分析

  • 首先是结论:点 ( x 0 , y 0 ) (x_0, y_0) (x0,y0)是可见的    ⟺    \iff x 0 , y 0 x_0, y_0 x0,y0是互质的。下面证明这个结论。

  • 首先是充分性:反证法,如果 ( x 0 , y 0 ) (x_0, y_0) (x0,y0)不是互质的,设其最大公约数为d,则d > 1,因此 ( x 0 d , y 0 d ) (\frac{x_0}{d}, \frac{y_0}{d}) (dx0,dy0)会把 ( x 0 , y 0 ) (x_0, y_0) (x0,y0)遮住(因为斜率相同),充分性成立。

  • 必要性:反证法,如果 ( x 0 , y 0 ) (x_0, y_0) (x0,y0)是互质的,但是不可见,则说明一定存在 x < x 0 , y < y 0 x < x_0, y < y_0 x<x0,y<y0使得 y 0 x 0 = = y x \frac{y_0}{x_0} == \frac{y}{x} x0y0==xy,说明可以被约分,则推出 ( x 0 , y 0 ) (x_0, y_0) (x0,y0)不是互质的,矛盾,必要性成立。

  • 因此本题中相当于让我们求解对于 0 ≤ x , y ≤ N 0 \le x, y \le N 0x,yN,有多少数对 ( x , y ) (x, y) (x,y)是互质的。我们可以先考虑一般的情况,如下图的右下部分:

在这里插入图片描述

只考虑右下部分,则和1互质的点为 ϕ ( 1 ) = 1 \phi(1) = 1 ϕ(1)=1个,和2互质的点有 ϕ ( 2 ) = 1 \phi(2) = 1 ϕ(2)=1个,…,和n互质的点有 ϕ ( n ) \phi(n) ϕ(n)个。

  • 因为对称性,上半部分的数量等于下半部分的数量,答案为

∑ i = 1 n ϕ ( i ) + 1 \sum _ {i = 1} ^ n \phi(i) + 1 i=1nϕ(i)+1

代码

  • C++
#include <iostream>

using namespace std;

const int N = 1010;

int primes[N], cnt;
bool st[N];
int phi[N];

// 筛法求欧拉函数
void init(int n) {
    
    phi[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] * i <= n; j++) {
            st[i * primes[j]] = true;
            if (i % primes[j] == 0) {
                phi[i * primes[j]] = phi[i] * primes[j];
                break;
            }
            phi[i * primes[j]] = phi[i] * (primes[j] - 1);
        }
    }
}

int main() {
    
    init(N - 1);
    
    int n, m;
    cin >> m;
    for (int T = 1; T <= m; T++) {
        cin >> n;
        int res = 1;
        for (int i = 1; i <= n; i++) res += phi[i] * 2;
        cout << T << ' ' << n << ' ' << res << endl;
    }
    
    return 0;
}

AcWing 220. 最大公约数

问题描述

分析

  • 如果 ( x , y ) = p (x, y) = p (x,y)=p,且p是质数,则 ( x p , y p ) = 1 (\frac{x}{p}, \frac{y}{p})=1 (px,py)=1,说明 x p , y p \frac{x}{p}, \frac{y}{p} px,py互质,令 a = x p , b = y p a =\frac{x}{p}, b = \frac{y}{p} a=px,b=py,则相当于问在 1 ≤ a , b ≤ n p 1 \le a, b \le \frac{n}{p} 1a,bpn的条件下,互质的点对个数。和AcWing 201. 可见的点求解的内容很类似。

  • 对于1~n中所有的质数,都需要求互质点对的个数,下面考虑对于某一个质数p,如何求解,如下图:

在这里插入图片描述

  • 因此如果令 ϕ ( 1 ) = 0 \phi(1)=0 ϕ(1)=0,则对于对于当前考察的质数p,符合要求的点对数目为: 2 × ( ϕ ( 1 ) + ϕ ( 2 ) + . . . + ϕ ( n p ) + 1 2 \times (\phi(1) + \phi(2) + ... + \phi(\frac{n}{p}) + 1 2×(ϕ(1)+ϕ(2)+...+ϕ(pn)+1

  • 我们需要对于1~n中所有的质数计算上述表达式,最后相加,因此可以采用前缀和思想求解。

代码

  • C++
#include <iostream>

using namespace std;

typedef long long LL;

const int N = 1e7 + 10;

// 1e7的int和bool数组大小都为40MB,LL数组大小80MB,因此使用存储空间为200MB
int primes[N], cnt;
bool st[N];
int phi[N];
LL s[N];

void init(int n) {
    
    // 默认phi[1] == 0
    for (int i = 2; i <= n; i++) {
        if (!st[i]) {
            primes[cnt++] = i;
            phi[i] = i - 1;
        }
        for (int j = 0; primes[j] * i <= n; j++) {
            st[i * primes[j]] = true;
            if (i % primes[j] == 0) {
                phi[primes[j] * i] = phi[i] * primes[j];
                break;
            }
            phi[primes[j] * i] = phi[i] * (primes[j] - 1);
        }
    }
    
    for (int i = 1; i <= n; i++) s[i] = s[i - 1] + phi[i];
}

int main() {
    
    int n;
    cin >> n;
    
    init(n);
    
    LL res = 0;
    for (int i = 0; i < cnt; i++) {
        int p = primes[i];
        res += s[n / p] * 2 + 1;
    }
    
    cout << res << endl;
    
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值