快轉到主要內容

CSES-1712 Exponentiation II

目錄


題目連結:https://cses.fi/problemset/task/1712

題意
#

這題是上一題 Exponentiation 的進階版。
給你三個數字 \(a, b, c\),求出 \(a^{b^c} \pmod{10^9+7}\) 的結果。

思路
#

如果直接算 \(b^c\),數字絕對會大到無法儲存。
而且我們也不能直接對指數 \(b^c\) 取模 \(10^9+7\),因為指數運算不符合一般的同餘律。

這時候就必須搬出「費馬小定理 (Fermat’s Little Theorem)」。

費馬小定理說,如果 \(p\) 是質數,而且 \(a\) 不是 \(p\) 的倍數,那麼 \(a^{p-1} \equiv 1 \pmod p\)。
這意味著,在底數為 \(a\) 且模數為質數 \(p\) 的情況下,指數的增長是每 \(p-1\) 為一個循環。

由於題目給的模數 \(10^9+7\) 剛好是一個質數。
所以我們在運算指數 \(b^c\) 的時候,其實只需要對 \(10^9+6\) 取模就行了。

也就是說,\(a^{b^c} \pmod{10^9+7}\) 會等於 \(a^{(b^c \pmod{10^9+6})} \pmod{10^9+7}\)。

實作上一樣用快速冪,只不過現在快速冪函式可以接收「自訂模數」。
我們先算出 \(b^c \pmod{10^9+6}\) 的結果,再把它當成新的指數。
最後拿去算底數為 \(a\)、對 \(10^9+7\) 取模的快速冪即可。

程式碼
#

#include <bits/stdc++.h>
using namespace std;

#define pb push_back
#define fi first
#define se second
#define INF LONG_LONG_MAX/1000
#define WA() cin.tie(0)->sync_with_stdio(0)
#define all(x) (x).begin(), (x).end()
#define int long long
#define PII pair<int, int>

int p = 1e9+7; // 基礎模數

// 可自訂模數 m 的快速冪函式
int f(int n, int x, int m) {
    int ret = 1;
    for (; x; x>>=1, n = n*n%m) {
        if (x&1) ret = ret*n%m;
    }
    return ret;
}

signed main() { WA();
    int t;
    // 讀取多筆測資
    for (cin >> t; t--;) {
        int a, b, c; cin >> a >> b >> c;
        // 先計算指數部分:b 的 c 次方,對 p-1 (也就是 10^9+6) 取模
        // 再計算底數部分:a 的 (剛算出來的結果) 次方,對 p (也就是 10^9+7) 取模
        cout << f(a, f(b, c, p-1), p) << '\n';
    }
}
Piau 的筆記本
作者
Piau 的筆記本
希望我寫下來的東西能夠長久的記在我的腦中