「扩展欧拉定理」P5091 【模板】扩展欧拉定理

知识点: 扩展欧拉定理

原题面


题意简述

给定 \(a,b,m\),求 \(a^b\pmod m\)
\(1\le a \le 10^9, 1\le b\le 10^{20000000}, 1\le m\le 10^8\)


分析题意

\(b\) 后面这是一大串什么啊。
直接做必爆炸,考虑用什么东西来降幂。
发现模数 \(m\) 较小,\(O(m)\) 可过,考虑使复杂度只与 \(m\) 有关。
考虑扩展欧拉定理。

\[a^b\equiv \begin{cases}a^b&b<\varphi(m)\\ a^{b\bmod\varphi(m)+\varphi(m)}&b\ge\varphi(m) \end{cases} \]


需要先求得 \(\varphi(m)\) 的值。
考虑欧拉函数的性质,有下式:

\[\varphi(m) = m \times \prod\limits_{i=1}^{x}1-\dfrac{1}{p_i} \]

\(m\) 的一质因子 \(p_i\)\(\varphi (m)\) 的贡献为 \(\dfrac{p_i-1}{p_i}\)
考虑质因数分解 \(m\),试除即可。
注意不要遗漏 \(\ge \sqrt{m}\) 的至多一个质因子。


求得 \(\varphi(m)\) 后,套用公式降幂即可。
可使用快速幂进一步优化复杂度。

总复杂度 \(O(\sqrt{m} + \log m)\)


代码实现

//知识点:欧拉定理
/*
By:Luckyblock
*/
#include <cstdio>
#include <ctype.h>
#include <cstring>
#include <algorithm>
#define ll long long
//=============================================================
int a, b, m, phi, ans = 1;
bool flag;
//=============================================================
inline int read() {
  int f = 1, w = 0; char ch = getchar();
  for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) {
    w = (w << 3) + (w << 1) + (ch ^ '0');
    if (w >= phi) {
      flag = true;
      w %= phi;
    }
  }
  return f * w;
}
void GetMax(int &fir, int sec) {
  if (sec > fir) fir = sec;
}
void GetMin(int &fir, int sec) {
  if (sec < fir) fir = sec;
}
void GetPhi() {
  int tmp = m; //用于质因数分解
  phi = m;
  for (int i = 2; i * i <= m; ++ i) {
    if (! (tmp % i)) {
      phi = phi - phi / i; //即 phi = phi*(1-1/i)
      while (! (tmp % i)) tmp /= i;
    }
  }
  if (tmp > 1) phi = phi - phi / tmp;
}
int QuickPow(int x, int y) {
  int ret = 1;
  while (y) {
    if (y & 1) ret = 1ll * ret * x % m;
    x = 1ll * x * x % m, y >>= 1;
  }
  return ret;
}
//=============================================================
int main() {
  scanf("%d%d", &a, &m);
  GetPhi();

  b = read();
  if (flag) b += phi;
  printf("%d", QuickPow(a, b));
  return 0;
}
posted @ 2020-08-04 14:57  Luckyblock  阅读(203)  评论(3编辑  收藏  举报