--- 这里是 cjiaw 的小窝(●'◡'●) ---

正在玩命加载中......

欧拉降幂

欧拉函数:

$\varphi(N) $ : 小于等于 N 且与 N 互质的正整数的个数

给出公式:

$\varphi(N) = N \times \frac{p_1-1}{p_1} \times \frac{p_2-1}{p_2} \times \dots \times \frac{p_m-1}{p_m}$

根据容斥原理 或 $\varphi(N) $为积性函数的性质可证明


欧拉定理:

对于整数 $m > 0$ 和整数 $a$ ,且 $\gcd(a,m)=1$ ,有:

$a^{\varphi(m)} \equiv 1 \pmod{m}$ 

扩展欧拉定理:

$a^b \equiv \begin{cases} a^b, & b < \varphi(m) \\ a^{(b \bmod \varphi(m)) + \varphi(m)}, & b \ge \varphi(m) \end{cases} \pmod{m}$


例题:P1405 苦恼的小明 - 洛谷

题意:

求:$a_1^{a_2^{a_3^{\cdots^{a_n}}}}$ mod10007 的值

思路:

为方便表达,这里把用 m 代表模数 10007

一、从最终目标倒推

我们要计算:$\text{ans} = a_1^{\,a_2^{\,a_3^{\,\cdots^{a_n}}}} \bmod m$

设整个幂塔为$P(1, n)$,其中$P(i, n) = a_i^{\,a_{i+1}^{\,\cdots^{a_n}}}$。

那么:

$P(1, n) = a_1^{\,P(2, n)} \bmod m$

二、应用欧拉降幂

根据扩展欧拉定理(当指数足够大时):

$a_1^{\,P(2, n)} \bmod m = a_1^{\,P(2, n) \bmod \varphi(m) + \varphi(m)} \bmod m$

关键:要计算这个值,我们需要知道$P(2, n) \bmod \varphi(m)$。

所以,问题转化为计算:

$P(2, n) \bmod \varphi(m)$

其中$P(2, n) = a_2^{\,a_3^{\,\cdots^{a_n}}}$。

三、递归继续

计算$P(2, n) \bmod \varphi(m)$又是一个相同形式的问题:

$P(2, n) \bmod \varphi(m) = a_2^{\,P(3, n)} \bmod \varphi(m)$

再次应用欧拉降幂,我们需要知道$P(3, n) \bmod \varphi(\varphi(m))$。

四、模式出现了

$\begin{aligned}&\text{第1层(最外层)需要模数} \varphi^{(1)}(m) = m \\&\text{第2层需要模数} \varphi^{(2)}(m) = \varphi(m) \\&\text{第3层需要模数} \varphi^{(3)}(m) = \varphi(\varphi(m)) \\&\ldots \\&\text{第}k\text{层需要模数} \varphi^{(k)}(m)\end{aligned}$

其中$\varphi^{(k)}(m)$表示对$m$连续应用$k-1$次$\varphi$函数。


代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#include<map>
#include<bitset>
#include<tuple>
#include<unordered_map>
#define inf 72340172838076673
#define endl '\n'
#define F first
#define S second
#define mst(a,x) memset(a,x,sizeof (a))
using namespace std;
typedef pair<int, int> pii;

const int N = 1234568, m = 10007;

int n;
int h[N];
int M[20];

int getphi(int x) {
    int res = x;
    for (int i = 2; i <= sqrt(x); i++) {
        if (x % i == 0) {
            res = res / i * (i - 1);
            while (x % i == 0) x /= i;
        }
    }
    if (x > 1) res = res / x * (x - 1);
    return res;
}

int mod(int a, int b) {
    if (a >= b) return a % b + b;
    return a;
}

int qpow(int a, int b, int m) {
    int res = 1;
    while (b) {
        if (b & 1) res = mod(res * a, m);
        a = mod(a * a, m);
        b >>= 1;
    }
    return res;
}

void solve() {

    cin >> n;
    for (int i = 1; i <= n; i++) cin >> h[i];
    int idx = 0;
    M[++idx] = m;
    while (M[idx] > 1) {
        M[idx + 1] = getphi(M[idx]);
        idx++;
    }

    for (int i = n; i >= 2; i--) {
        int mi = min(i - 1, idx);
        h[i - 1] = qpow(h[i - 1], h[i], M[mi]);
    }

    cout << h[1] % m << endl;

}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);

    int T = 1;
    // cin >> T;
    while (T--) solve();

    return 0;
}

 

posted @ 2026-04-06 22:53  wwjjw  阅读(15)  评论(0)    收藏  举报