扩展欧拉定理

P5091 扩展欧拉定理

题目大意:

给定三个数,a, b, m, 求a ^ b % m的值。
1 <= b <= 10^20000000

思路

b的值非常大,直接用快速幂求值会TLE
考虑用扩展欧拉定理,将b降幂之后,再使用快速幂快速求结果

扩展欧拉定理:

\[设 \ ( a, m \in \mathbb{Z}^+ \ ),则: a^b \equiv \begin{cases} a^{b \bmod \phi(m)} &\pmod{m} & \text{若 } b < \phi(m), \\ a^{b \bmod \phi(m) + \phi(m)} &\pmod{m} & \text{若 } b \geq \phi(m). \end{cases} \]

代码

#include <bits/stdc++.h>
#define PRINT_PI(presision, value) std::cout << std::fixed << std::setprecision(presision) << (value) << std::endl
using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;
// 求m的欧拉函数值
i64 get_phi(i64 m) {
    i64 res = m;
    for (int i = 2; i * i <= m; i ++) {
        if (m % i == 0) { // 找到一个质因子
            res = res / i * (i-1); 
            while (m % i == 0) m /= i; // 把当前质因子除尽
        }
    }
    if (m > 1) res = res / m * (m-1); // 别忘了最后一个质因子
    return res;
}
i64 depow(i64 phi, std::string b) {
    // 扩展欧拉定理对b降幂,phi是模数的欧拉函数
    i64 res = 0;
    bool flag = false;
    // 用秦九韶算法对b进行模m意义下的化简,即扩展欧拉定理中的b % m的那一步,因为b非常大,直接取模不好算,因此用秦九韶算法化简
    for (int i = 0; b[i]; i ++) {
        res = res * 10 + (b[i] - '0');
        if (res >= phi) {
            flag = true;
            res %= phi;
        }
    }
    // 最后加上phi(m)
    if (flag) res += phi;
    return res;
}
i64 qmi(i64 a, i64 b, i64 m) {
    i64 res = 1;
    while (b) {
        if (b & 1) res = (res * a) % m;
        a = (a * a) % m;
        b >>= 1;
    }
    return res;
}
void solve() {
    // register 用于将局部变量存储到寄存器中,提高访问速度
    i64 a, m;
    std::cin >> a >> m;
    std::string b;
    std::cin >> b;
    // 求phi(m)的值:m的欧拉函数,用试除法
    i64 phi = get_phi(m);
    // 对b降幂
    i64 bb = depow(phi, b);
    // 用快速幂求a^b % m
    std::cout << qmi(a, bb, m) << "\n";
}
int main()
{   
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int t = 1; 
    // std::cin >> t;
    while (t --) {
        solve();
    }
    return 0;
}
posted @ 2025-05-18 15:31  来杯whiskey  阅读(30)  评论(0)    收藏  举报