Acwing 欧拉函数

1.求欧拉函数

欧拉函数phi(n):得到1~n中与n互质的数的个数

例如:phi(6) = 2,1 - 6 中与 6 互质的数为 1、5

a,b互质就是gcd(a,b) = 1
如何求解欧拉函数?

对于一个数N,可以分解质因数为
N = P 1 k 1 × P 2 k 2 × ⋯ × P n k n ,则 p h i ( N ) = N × ( 1 − 1 P 1 ) × ( 1 − 1 P 2 ) × ⋯ × ( 1 − 1 P n ) N = P_{1}^{k_{1}} \times P_{2}^{k_{2}} \times \dots \times P_{n}^{k_{n}},则phi(N) = N \times (1 - \frac{1}{P_{1}}) \times (1 - \frac{1}{P_{2}}) \times \dots \times (1 - \frac{1}{P_{n}}) N=P1k1×P2k2××Pnkn,则phi(N)=N×(1P11)×(1P21)××(1Pn1)
比如 6=2×3,则phi(6) = 6 * (1 - 1/2) * (1-1/3) = 2,即1~6中有两个与6互质的数;

欧拉函数的应用:

欧拉定理
若 a 与 n 互质,那么有 a ϕ ( n ) m o d   n = 1 若a与n互质,那么有a^{\phi(n)} mod \ n=1 an互质,那么有aϕ(n)mod n=1
费马定理:
若 a 与 p 互质, p 是质数,那么有 a ϕ ( p ) m o d   p = a p − 1 m o d   p = 1 若a与p互质,p是质数,那么有a^{\phi(p)} mod\ p = a^{p-1} mod\ p = 1 ap互质,p是质数,那么有aϕ(p)mod p=ap1mod p=1

定义求欧拉函数

Acwing 873.欧拉函数
在这里插入图片描述
实现思路:得到质因数,然后按公式相乘

注意:每次得到质因数i,应按照公式乘以(1-1/i),但为避免小数,先除再乘,即(1-1/i)=/i*(i-1),res初始化为x;

具体实现代码(详解版):

#include <iostream>

using namespace std;

// 计算单个数 x 的欧拉函数值 φ(x)
int phi(int x) {
    int res = x; // 初始时,欧拉函数的值设置为 x
    // 遍历所有可能的质因数 i,i 的范围从 2 到 sqrt(x)
    for (int i = 2; i <= x / i; i++) {
        if (x % i == 0) { // 如果 i 是 x 的质因数
            res = res / i * (i - 1); // 使用公式 φ(x) = φ(x) / i * (i - 1)
            while (x % i == 0) x /= i; // 不断除去 i,直到 x 不再能被 i 整除
        }
    }
    // 如果最后剩余的 x > 1,说明它本身是一个大于 sqrt(x) 的质数
    if (x > 1) res = res / x * (x - 1); // 使用公式 φ(x) = φ(x) / x * (x - 1)

    return res; 
}

int main() {
    int n;
    cin >> n; 
    while (n--) { 
        int x;
        cin >> x; 
        cout << phi(x) << endl; // 输出 x 的欧拉函数值
    }
    return 0;
}

2.筛法求欧拉函数

利用质数的线性筛法求1-n的欧拉函数

由于在线性筛法的执行过程中,对于质数会保留,对于合数会用其最小质因子筛掉。所以线性筛法是会访问到所有数的。而根据上面的推导,在遇到每种情况时,我们都能求出欧拉函数

  • 当i是质数:phi(i)=i-1,因为i为质数,那么前i-1个都与其互质

  • 当i是合数:

    某个合数一定是被pj * i 给筛掉的,我们就在筛他的时候求他的欧拉函数值

    1. 如果 i % pj == 0 ,那么pj就是i的某个质因数,那么pj*ii质因数组合完全相同,根据欧拉函数公式,所以phi(pj *i) = pj * phi(i)
    2. 如果i % pj != 0,pj不是i的质因数,那么pj*i的质因数组合就是i的质因数组合基础上加了一个质数pj,根据欧拉函数公式,所以phi(pj * i) = pj * phi(i) *(1 - 1/pj) = (pj - 1) * phi(i)

Acwing 874.筛法求欧拉函数
在这里插入图片描述
具体实现代码(详解版):

#include <iostream>

using namespace std;

typedef long long LL;

const int N = 1000010; // 最大范围 N

int primes[N], cnt; // primes[] 用于存储筛出的素数,cnt 记录素数的个数
int phi[N]; // phi[] 用于存储每个数的欧拉函数值
bool st[N]; // st[] 标记数组,用于标记某个数是否已经被筛掉(是否是合数)

// 计算 1 到 n 之间所有数的欧拉函数之和
LL get_eulers(int n) {
    phi[1] = 1; // 欧拉函数的初始值,φ(1) = 1
    
    // 线性筛法,计算欧拉函数
    for (int i = 2; i <= n; i++) {
        if (!st[i]) { // 如果 i 还没有被标记,说明 i 是素数
            primes[cnt++] = i; // 将 i 加入素数数组
            phi[i] = i - 1; // 对于素数 i,有 φ(i) = i - 1
        }
        // 枚举每个素数 primes[j],并标记 primes[j] * i 为合数
        for (int j = 0; primes[j] <= n / i; j++) {
            st[primes[j] * i] = true; // 标记 primes[j] * i 为合数
            
            if (i % primes[j] == 0) { // 如果 i 能被 primes[j] 整除
                // 说明 primes[j] 是 i 的最小质因数,直接使用公式 φ(primes[j] * i) = φ(i) * primes[j]
                phi[primes[j] * i] = phi[i] * primes[j];
                break; // 因为 primes[j] 是 i 的最小质因数,故无需继续枚举
            }
            
            // 如果 i 不能被 primes[j] 整除,使用公式 φ(primes[j] * i) = φ(i) * (primes[j] - 1)
            phi[primes[j] * i] = phi[i] * (primes[j] - 1);
        }
    }

    // 累加 1 到 n 的所有欧拉函数值
    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; // 输出从 1 到 n 的欧拉函数之和
    
    return 0;
}

总结:

  • 方法一(直接计算):适合当你只需要计算单个或少量数字的欧拉函数时,使用这种方法简单有效。
  • 方法二(线性筛法):适合处理大量数字的欧拉函数计算,如 1 到 𝑛 的所有数字,或者需要频繁查询时,先预处理一次后可以快速查找。
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值