《P5091 【模板】扩展欧拉定理》

题目背景

出题人也想写有趣的题面,可惜并没有能力。

题目描述

给你三个正整数,a,m,b,你需要求:abmodm

输入格式

一行三个整数,a,m,b

输出格式

一个整数表示答案

输入输出样例

输入 #1复制

复制代码
2 7 4

输出 #1复制

复制代码
2

输入 #2复制

复制代码
998244353 12345 98765472103312450233333333333

输出 #2复制

复制代码
5333

说明/提示

注意输入格式,a,m,b 依次代表的是底数、模数和次数

【样例 1 解释】

24mod7=2

【数据范围】

对于 100% 的数据,1≤a≤109,1≤b≤1020000000,1≤m≤108。

代码实现:

复制代码
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

typedef long long ll;
const int ML = 2e7 + 10, MN = 1e4 + 10;
int pr[MN], pn;
bool v[MN];
int f[12], c;
int a, m;

ll qp(ll x, ll y, ll mod) {
    x %= mod;
    ll res = 1;
    while (y) {
        if (y & 1) res = res * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return res;
}

int rm(int m) {
    char ch;
    while (!isdigit(ch = getchar()));
    int x = 0;
    bool fl = false;
    for (; isdigit(ch); ch = getchar()) {
        x = x * 10 + ch - '0';
        if (x >= m) fl = 1, x %= m;
    }
    return fl ? x + m : x;
}

void sol() {
    v[0] = v[1] = true;
    for (int i = 2; i < MN; ++i) {
        if (!v[i]) {
            pr[pn++] = i;
            for (int j = i + i; j < MN; j += i) v[j] = true;
        }
    }
    int mm = m;
    for (int i = 0; i < pn && (ll)pr[i] * pr[i] <= m; ++i) {
        if (mm % pr[i] == 0) {
            f[c++] = pr[i];
            while (mm % pr[i] == 0) mm /= pr[i];
        }
    }
    if (mm > 1) f[c++] = mm;
    int ph = m;
    for (int i = 0; i < c; ++i) {
        ph /= f[i];
        ph *= (f[i] - 1);
    }
    printf("%lld\n", qp(a, rm(ph), m));
}

int main() {
    scanf("%d%d", &a, &m);
    sol();
    return 0;
}