【数论】欧拉定理 && 扩展欧拉定理

文章目录

  • 前置知识
  • 一、欧拉定理
  • 二、扩展欧拉定理
    • [1. 扩展欧拉定理的内容](#1. 扩展欧拉定理的内容)
    • [2. 扩展欧拉定理的证明](#2. 扩展欧拉定理的证明)
    • [3. 应用:欧拉降幂](#3. 应用:欧拉降幂)
    • [4. 【模板】扩展欧拉定理 ⭐⭐⭐⭐](#4. 【模板】扩展欧拉定理 ⭐⭐⭐⭐)
  • [三、练习:上帝与集合的正确用法 ⭐⭐⭐⭐](#三、练习:上帝与集合的正确用法 ⭐⭐⭐⭐)
    • [1. 解题思路](#1. 解题思路)
    • [2. 代码实现](#2. 代码实现)

前置知识

一、欧拉定理

1. 欧拉定理的内容

欧拉定理 :若 a , n a,n a,n 均为正整数,且 gcd ⁡ ( a , n ) = 1 \gcd(a,n)=1 gcd(a,n)=1,则
a φ ( n ) ≡ 1 ( m o d n ) a^{\varphi(n)}\equiv1\pmod n aφ(n)≡1(modn)

如果你知道费马小定理,那么这个欧拉定理你一定觉得很眼熟。费马小定理:
a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv1\pmod p ap−1≡1(modp)

其中 p p p 是素数,又根据我们欧拉函数的性质可知, φ ( p ) = p − 1 \varphi(p) = p - 1 φ(p)=p−1,所以费马小定理实际上就是欧拉定理的一种特殊情况。


2.欧拉定理的证明

:设小于 n n n 且与 n n n 互素的所有正整数构成一个集合 Z n = { x 1 , x 2 , ⋯ x φ ( n ) } \Z_n=\{x_1,x_2,\cdots x_{\varphi(n)}\} Zn={x1,x2,⋯xφ(n)},共 φ ( n ) \varphi(n) φ(n) 个元素。

现在,我将把 Z n \Z_n Zn 中的每个元素进行一个运算得到另一个值 m m m:
a x 1   m o d   n = m 1 a x 2   m o d   n = m 2 ⋮ a x φ ( n )   m o d   n = m φ ( n ) ax_1\bmod n=m_1\\ ax_2\bmod n=m_2\\ \vdots\\ ax_{\varphi(n)}\bmod n=m_{\varphi(n)} ax1modn=m1ax2modn=m2⋮axφ(n)modn=mφ(n)

知道 m m m 是怎么来的之后,现在我把这所有的 m m m 组成一个新的集合 S = { m 1 , m 2 , ⋯ m φ ( x ) } S=\{m_1,m_2,\cdots m_{\varphi(x)}\} S={m1,m2,⋯mφ(x)},共 φ ( n ) \varphi(n) φ(n) 个元素。

现在我说 Z n = S \Z_n=S Zn=S 你信吗?不妨来证明一下:

由最开始的条件可知, a a a 与 n n n 互素,集合 Z n \Z_n Zn 中的任意一个元素 x i x_i xi 也与 n n n 互素。那么易知它们的乘积 a x i ax_i axi 同样也与 n n n 互素。这是因为 a a a 和 x i x_i xi 都无法拆分出一个 n n n 的约数,那它们的乘积当然也就拆不出这么一个数,因此互素。又因为 m m m 的值是通过 a x i ax_i axi 模 n n n 得到的,这么做并不会改变数与模数之间的最大公约数,所以可以推出 m m m 与 n n n 互素。

简而言之就是
( a , n ) = 1 , ( x i , n ) = 1 ⇒ ( a x i , n ) = 1 ⇒ ( m i , n ) = 1 (1) (a,n)=1,(x_i,n)=1\ \Rightarrow\ (ax_i,n)=1\ \Rightarrow \ (m_i,n)=1\tag1 (a,n)=1,(xi,n)=1 ⇒ (axi,n)=1 ⇒ (mi,n)=1(1)

又由于 Z n \Z_n Zn 中的元素介于 n n n 之间,任意两个元素之间互不相等,于是无论它们模 n n n 还是乘以 a a a 之后模 n n n,都是不相等的:
x i ≠ x j ⇒ ( x i   m o d   n ) ≠ ( x j   m o d   n ) ⇒ ( a x i   m o d   n ) ≠ ( a x j   m o d   n ) ⇓ m i ≠ m j (2) x_i\ne x_j\ \ \Rightarrow\ \ (x_i\bmod n)\ne (x_j\bmod n)\ \ \Rightarrow\ \ (ax_i\bmod n)\ne (a x_j\bmod n)\\ \Downarrow\\ m_i\ne m_j\tag2 xi=xj ⇒ (ximodn)=(xjmodn) ⇒ (aximodn)=(axjmodn)⇓mi=mj(2)

因此,上面的(1)和(2)式就说明了一件事情:集合 S S S 中的元素与 n n n 互素且与互不相等。那我们都知道,这样的集合肯定是唯一确定的,那这不就是集合 Z n \Z_n Zn 吗?因此我们得出了 一个很重要的结论:
Z n = S \Z_n=S Zn=S

于是这两个集合内的每个元素相乘最后的结果肯定相等,即
∏ n = 1 φ ( n ) x i = ∏ n = 1 φ ( n ) m i \prod_{n=1}^{\varphi(n)}x_i=\prod_{n=1}^{\varphi(n)}m_i n=1∏φ(n)xi=n=1∏φ(n)mi

因此它们模 n n n 之后也相等,即
∏ n = 1 φ ( n ) x i   m o d   n = ∏ n = 1 φ ( n ) m i   m o d   n \prod_{n=1}^{\varphi(n)}x_i\bmod n=\prod_{n=1}^{\varphi(n)}m_i\bmod n n=1∏φ(n)ximodn=n=1∏φ(n)mimodn

我们对这个这个等式做进一步分析
∏ n = 1 φ ( n ) x i   m o d   n = ∏ n = 1 φ ( n ) m i   m o d   n = ( m 1 ⋅ m 2 ⋅ ⋯ m φ ( n ) )   m o d   n = [ ( a x 1   m o d   n ) ⋯ ( a x φ ( n )   m o d   n ) ]   m o d   n \begin{aligned}\prod_{n=1}^{\varphi(n)}x_i\bmod n&=\prod_{n=1}^{\varphi(n)}m_i\bmod n\\ &=(m_1\cdot m_2\cdot\cdots m_{\varphi(n)})\bmod n\\ &=[(ax_1\bmod n)\cdots(ax_{\varphi(n)}\bmod n)]\bmod n\end{aligned} n=1∏φ(n)ximodn=n=1∏φ(n)mimodn=(m1⋅m2⋅⋯mφ(n))modn=[(ax1modn)⋯(axφ(n)modn)]modn

由模运算的性质可知,该等式可以进一步转化为
= ( a x 1 ⋅ a x 2 ⋅ ⋯ a x φ ( n ) )   m o d   n =(ax_1\cdot ax_2\cdot\cdots ax_{\varphi(n)})\bmod n =(ax1⋅ax2⋅⋯axφ(n))modn

将所有的 a a a 合并,即
= ( a φ ( n ) ⋅ x 1 ⋅ x 2 ⋯ x φ ( n ) )   m o d   n = ( a φ ( n ) ∏ n = 1 φ ( n ) x i )   m o d   n \begin{aligned}&=(a^{\varphi(n)}\cdot x_1\cdot x_2\cdots x_{\varphi(n)})\bmod n\\ &=(a^{\varphi(n)}\prod_{n=1}^{\varphi(n)}x_i)\bmod n\end{aligned} =(aφ(n)⋅x1⋅x2⋯xφ(n))modn=(aφ(n)n=1∏φ(n)xi)modn

做了一长串运算,最终得到了下面的等式
( a φ ( n ) ∏ n = 1 φ ( n ) x i )   m o d   n = ∏ n = 1 φ ( n ) x i   m o d   n (a^{\varphi(n)}\prod_{n=1}^{\varphi(n)}x_i)\bmod n=\prod_{n=1}^{\varphi(n)}x_i\bmod n (aφ(n)n=1∏φ(n)xi)modn=n=1∏φ(n)ximodn

根据同余的性质,我们可以两边同时去除以 ∏ n = 1 φ ( n ) x i \prod_{n=1}^{\varphi(n)}x_i ∏n=1φ(n)xi,最终得到
a φ ( n )   m o d   n = 1   m o d   n ⇓ a φ ( n ) ≡ 1 ( m o d n ) a^{\varphi(n)}\bmod n=1\bmod n\\ \Downarrow\\ a^{\varphi(n)}\equiv1\pmod n aφ(n)modn=1modn⇓aφ(n)≡1(modn)

欧拉定理,证毕!


二、扩展欧拉定理

欧拉定理也就看个乐呵,真正有用的还是扩展欧拉定理。

1. 扩展欧拉定理的内容

顾名思义,这是欧拉定理的拓展,也就是一般形式。

对于任意的正整数 a , b , n a,b,n a,b,n ,若 b ≥ φ ( n ) b\geq\varphi(n) b≥φ(n) ,则有

a b ≡ a b   m o d   φ ( n ) + φ ( n ) ( m o d n ) ( b ≥ φ ( n ) ) a^b\equiv a^{b\bmod \varphi (n)+\varphi(n)}\pmod n\\ (b\geq\varphi(n)) ab≡abmodφ(n)+φ(n)(modn)(b≥φ(n))

如果 b ≥ φ ( n ) b\geq\varphi(n) b≥φ(n),那么直接就是 a b ≡ a b ( m o d n ) a^b\equiv a^b \pmod n ab≡ab(modn)。


2. 扩展欧拉定理的证明

  • 引理 1

a b ≡ a b   m o d   φ ( n ) ( m o d n ) a^b\equiv a^{b\bmod\varphi(n)}\pmod n ab≡abmodφ(n)(modn)

:我们都知道欧拉定理,即当 gcd ⁡ ( a , n ) = 1 \gcd(a,n)=1 gcd(a,n)=1,有
a φ ( n ) ≡ 1 ( m o d n ) a^{\varphi(n)}\equiv1\pmod n aφ(n)≡1(modn)

现在不妨设 b = k φ ( n ) + t , t = b   m o d   φ ( n ) b=k\varphi(n)+t,t=b\bmod\varphi(n) b=kφ(n)+t,t=bmodφ(n),其中 k ∈ Z k\in \Z k∈Z。

那么就有
a b   m o d   n = a k φ ( n ) + t   m o d   n = ( a φ ( n ) ) k ⋅ a t   m o d   n \begin{aligned}a^b\bmod n&=a^{k\varphi(n)+t}\bmod n\\ &=(a^{\varphi(n)})^k\cdot a^t\bmod n\end{aligned} abmodn=akφ(n)+tmodn=(aφ(n))k⋅atmodn

根据欧拉定理以及模运算的性质,可得
= 1 k ⋅ a t   m o d   n = a b   m o d   φ ( n )   m o d   n \begin{aligned}&=1^k\cdot a^t\bmod n\\ &=a^{b\bmod\varphi(n)}\bmod n\end{aligned} =1k⋅atmodn=abmodφ(n)modn

综上,我们就得到了
a b   m o d   n = a b   m o d   φ ( n )   m o d   n ⇓ a b ≡ a b   m o d   φ ( n ) ( m o d n ) a^b\bmod n=a^{b\bmod\varphi(n)}\bmod n\\ \Downarrow\\ a^b\equiv a^{b\bmod\varphi(n)}\pmod n abmodn=abmodφ(n)modn⇓ab≡abmodφ(n)(modn)

而这个式子,就是欧拉定理的推论,这里把它叫做引理 1。

  • 引理 2

若 p p p 是素数, q q q 是正整数且 q > 1 q>1 q>1,则
φ ( p q ) ≥ q \varphi(p^q)\geq q φ(pq)≥q

**证:**由前面提到的欧拉函数的性质可知
φ ( p q ) = p q − p q − 1 = p q − 1 ( p − 1 ) φ(p^q) = p^q - p^{q-1} = p^{q-1}(p - 1)\ φ(pq)=pq−pq−1=pq−1(p−1)

  • 当 p , q p,q p,q 都为 2 2 2 时,易知 φ ( 4 ) = 2 ≥ 2 \varphi(4)=2\geq2 φ(4)=2≥2 没毛病;

  • 当 p = 2 , q > 2 p=2,q>2 p=2,q>2 时, q q q 每增加 1 1 1,由上面的式子可知 φ ( p q ) φ(p^q) φ(pq) 是成倍成倍地增加,因此肯定不等式左边比右边增加快得多,因此成立;

  • 当 q = 2 , p > 2 q=2,p>2 q=2,p>2 时, p p p 在增加的时候, φ ( p q ) φ(p^q) φ(pq) 自然也在增加,而不等式右边的值不变,因此同样成立。

  • 扩展欧拉定理的证明

① 当 gcd ⁡ ( a , n ) = 1 \gcd(a,n)=1 gcd(a,n)=1 时,由同余的性质
a φ ( n ) ≡ 1 ( m o d n ) , a b ≡ a b   m o d   φ ( n ) ( m o d n ) ⇓ a b ≡ a b   m o d   φ ( n ) + φ ( n ) ( m o d n ) a^{\varphi(n)}\equiv1\pmod n\ ,\ a^b\equiv a^{b\bmod\varphi(n)}\pmod n\\ \Downarrow\\ a^b\equiv a^{b\bmod \varphi (n)+\varphi(n)}\pmod n aφ(n)≡1(modn) , ab≡abmodφ(n)(modn)⇓ab≡abmodφ(n)+φ(n)(modn)

显然成立。

② 当 gcd ⁡ ( a , n ) ≠ 1 \gcd(a,n)\ne1 gcd(a,n)=1 时,我们对 n n n 进行标准素因子分解,可得
n = p 1 q 1 p 2 q 2 ⋯ p s q s = ∏ i = 1 s p i q i n={p_1}^{q_1}{p_2}^{q_2}\cdots {p_s}^{q_s}=\prod_{i=1}^{s}p_i^{q_i} n=p1q1p2q2⋯psqs=i=1∏spiqi

这个时候我们只需要证明对于任意一个 p i q i p_i^{q_i} piqi,都有 a b ≡ a b   m o d   φ ( n ) + φ ( n ) ( m o d p i q i ) a^b\equiv a^{b\bmod \varphi (n)+\varphi(n)}\pmod{ p_i^{q_i}} ab≡abmodφ(n)+φ(n)(modpiqi) 成立即可 。何以见得?因为根据同余的一个很重要的性质,若
x ≡ y ( m o d n 1 ) , x ≡ y ( m o d n 2 ) ⇓ x ≡ y ( m o d Lcm ⁡ [ n 1 , n 2 ] ) x\equiv y\pmod {n_1},x\equiv y\pmod {n_2}\\ \Downarrow\\ x\equiv y\pmod {\operatorname {Lcm} [n_1,n_2]} x≡y(modn1),x≡y(modn2)⇓x≡y(modLcm[n1,n2])

而由于我们这里的 p i q i p_i^{q_i} piqi 之间一定是互素的,因此当所有的 p i q i p_i^{q_i} piqi 都满足条件时,他们的最小公倍数也就是他们全部乘起来,即 n n n。

由于 gcd ⁡ ( a , n ) ≠ 1 \gcd(a,n)\ne1 gcd(a,n)=1 ,说明 a a a 肯定是至少是某一个 p i q i p_i^{q_i} piqi 的倍数。这个时候我们再分类讨论一下:

(Ⅰ) 当 gcd ⁡ ( a , p i q i ) = 1 \gcd(a,p_i^{q_i})=1 gcd(a,piqi)=1 时

由引理 1我们知道 a b ≡ a b   m o d   φ ( n ) ( m o d n ) a^b\equiv a^{b\bmod\varphi(n)}\pmod n ab≡abmodφ(n)(modn),而这个 n n n 是 p i q i p_i^{q_i} piqi 的倍数,不难发现,如果我把这里的模数 n n n 缩小一定的倍数,即缩小到 p i q i p_i^{q_i} piqi,这个引理 1的式子依旧是成立的,于是有
a b ≡ a b   m o d   φ ( n ) ( m o d p i q i ) a^b\equiv a^{b\bmod\varphi(n)}\pmod {p_i^{q_i}} ab≡abmodφ(n)(modpiqi)

同理有
a φ ( n ) ≡ 1 ( m o d p i q i ) a^{\varphi(n)}\equiv1\pmod {p_i^{q_i}} aφ(n)≡1(modpiqi)

两边相乘即有
a b ≡ a b   m o d   φ ( n ) + φ ( n ) ( m o d p i q i ) a^b\equiv a^{b\bmod \varphi (n)+\varphi(n)}\pmod{ p_i^{q_i}} ab≡abmodφ(n)+φ(n)(modpiqi)

情况 (Ⅰ) 证毕。

(Ⅱ) 当 gcd ⁡ ( a , p i q i ) ≠ 1 \gcd(a,p_i^{q_i})\ne1 gcd(a,piqi)=1 时

这种情况下, a a a 必然是 p i p_i pi 的倍数,假设 a = k p a=kp a=kp

这时就要用到我们的引理 2 了,我们都知道前提条件 b ≥ φ ( n ) b\geq\varphi(n) b≥φ(n) 以及引理 2 证明过的 φ ( p i q i ) ≥ q i \varphi(p_i^{q_i})\geq q_i φ(piqi)≥qi,因此有:
b ≥ φ ( n ) ≥ φ ( p i q i ) ≥ q i b\geq\varphi(n)\geq\varphi(p_i^{q_i})\geq q_i b≥φ(n)≥φ(piqi)≥qi

我们得到了 b ≥ q i b\geq q_i b≥qi,这可不得了了,那么我们就注意到此时 a b = ( k p ) b = k b p b a^b=(kp)^b=k^bp^b ab=(kp)b=kbpb 一定是 p i q i p_i^{q_i} piqi 的倍数

而 a b   m o d   φ ( n ) + φ ( n ) a^{b\bmod \varphi (n)+\varphi(n)} abmodφ(n)+φ(n) 也一定是 p i q i p_i^{q_i} piqi 的倍数!

因此既然这样,我们也就可以写出
a b ≡ a b   m o d   φ ( n ) + φ ( n ) ≡ 0 ( m o d p i q i ) a^b\equiv a^{b\bmod \varphi (n)+\varphi(n)}\equiv 0\pmod{ p_i^{q_i}} ab≡abmodφ(n)+φ(n)≡0(modpiqi)

证毕!


3. 应用:欧拉降幂

当我们计算 a b   m o d   p a^b \bmod p abmodp 时,我们通常采用快速幂来运算,但是当 b b b 非常非常非常大的时候,快速幂也显得有点乏力,此时我们可以用扩展欧拉定理去把 b b b 缩小,之后再采用快速幂运算就会快很多。

举个简单的例子:计算
99824435 3 98765472103312450233333333333 m o d    12345 998244353^{98765472103312450233333333333} \mod 12345 99824435398765472103312450233333333333mod12345

的时候,我们不能直接用快速幂,这个时候显然 98765472103312450233333333333 > φ ( 12345 ) 98765472103312450233333333333 > \varphi(12345) 98765472103312450233333333333>φ(12345),所以根据扩展欧拉定理,等价于计算
99824435 3 98765472103312450233333333333   m o d   φ ( 12345 ) + φ ( 12345 ) m o d    12345 998244353^{98765472103312450233333333333 \bmod \varphi(12345) + \varphi(12345)} \mod 12345 99824435398765472103312450233333333333modφ(12345)+φ(12345)mod12345

最终的指数顶多也就 5 5 5 位数,之后再用快速幂就会快很多。


4. 【模板】扩展欧拉定理 ⭐⭐⭐⭐

【题目链接】

P5091 【模板】扩展欧拉定理 - 洛谷

【题目描述】

给你三个正整数, a , m , b a,m,b a,m,b,你需要求: a b   m o d   m a^b \bmod m abmodm

【输入格式】

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

【输出格式】

一个整数表示答案

【示例一】

输入

复制代码
2 7 4

输出

复制代码
2

【示例二】

输入

复制代码
998244353 12345 98765472103312450233333333333

输出

复制代码
5333

【说明/提示】

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

【样例 1 1 1 解释】
2 4   m o d   7 = 2 2^4 \bmod 7 = 2 24mod7=2

【数据范围】

对于 100 % 100\% 100% 的数据, 1 ≤ a ≤ 1 0 9 1\le a \le 10^9 1≤a≤109, 1 ≤ b ≤ 1 0 20000000 , 1 ≤ m ≤ 1 0 8 1\le b \le 10^{20000000},1\le m \le 10^8 1≤b≤1020000000,1≤m≤108。

cpp 复制代码
#include<iostream>

using namespace std;

typedef long long LL;

LL a, m;
string s;  // 由于 b 很大, 只能用 string 来存储

// 公式法求单个数的欧拉函数
LL get_phi(LL x)
{
    LL ret = x;
    for(int i = 2; i <= x / i; i++)
    {
        if(x % i == 0)
        {
            ret = ret / i * (i - 1);
            while(x % i == 0) x /= i;
        }
    }
    if(x > 1) ret = ret / x * (x - 1);
    return ret;
}

// 秦九韶 + 扩展欧拉
LL get_b(string& s, LL phi)
{
    // flag 标记 b 是否大于等于 phi(m)
    bool flag = false;
    LL ret = 0;
    for(auto& ch : s)
    {
        ret = ret * 10 + ch - '0';
        // 如果 b >= phi(m), 此时满足降幂的使用条件
        if(ret >= phi)
        {
            flag = true;
            ret %= phi;  // 扩展欧拉
        }
    }
    if(flag) ret += phi;  // 扩展欧拉
    return ret;
}

// 快速幂
LL qpow(LL a, LL n, LL p)
{
    int ret = 1;
    while(n)
    {
        if(n & 1) ret = ret * a % p;
        n >>= 1;
        a = a * a % p;
    }
    return ret;
}

int main()
{
    cin >> a >> m >> s;
    LL phi_m = get_phi(m);
    LL b = get_b(s, phi_m);

    cout << qpow(a, b, m) << endl;

    return 0;
}

三、练习:上帝与集合的正确用法 ⭐⭐⭐⭐

题目链接

P4139 上帝与集合的正确用法 - 洛谷

【题目描述】

根据一些书上的记载,上帝的一次失败的创世经历是这样的:

第一天,上帝创造了一个世界的基本元素,称做元。

第二天,上帝创造了一个新的元素,称作 α \alpha α 。 α \alpha α 被定义为元构成的集合。容易发现,一共有两种不同的 α \alpha α 。

第三天,上帝又创造了一个新的元素,称作 β \beta β 。 β \beta β 被定义为 α \alpha α 构成的集合。容易发现,一共有四种不同的 β \beta β。

第四天,上帝创造了新的元素 γ \gamma γ, γ \gamma γ 被定义为 β \beta β 的集合。显然,一共会有 16 16 16 种不同的 γ \gamma γ。

如果按照这样下去,上帝创造的第四种元素将会有 65536 65536 65536 种,第五种元素将会有 2 65536 2^{65536} 265536种。这将会是一个天文数字。

然而,上帝并没有预料到元素种类数的增长是如此的迅速。他想要让世界的元素丰富起来,因此,日复一日,年复一年,他重复地创造着新的元素......

然而不久,当上帝创造出最后一种元素 θ \theta θ 时,他发现这世界的元素实在是太多了,以致于世界的容量不足,无法承受。因此在这一天,上帝毁灭了世界。

至今,上帝仍记得那次失败的创世经历,现在他想问问你,他最后一次创造的元素 θ \theta θ 一共有多少种?

上帝觉得这个数字可能过于巨大而无法表示出来,因此你只需要回答这个数对 p p p 取模后的值即可。

你可以认为上帝从 α \alpha α 到 θ \theta θ 一共创造了 1 0 9 10^9 109 次元素,或 1 0 18 10^{18} 1018 次,或者干脆 ∞ \infty ∞ 次。

【一句话题意】

定义 a 0 = 1 , a n = 2 a n − 1 a_0=1,a_n=2^{a_{n-1}} a0=1,an=2an−1,可以证明 b n = a n   m o d   p b_n=a_n\bmod p bn=anmodp 在某一项后都是同一个值,求这个值。

【输入格式】

第一行一个整数 T T T,表示数据个数。

接下来 T T T 行,每行一个正整数 p p p,代表你需要取模的值。

【输出格式】

T T T 行,每行一个正整数,为答案对 p p p 取模后的值。

【示例一】

输入

复制代码
3
2
3
6

输出

复制代码
0
1
4

【说明/提示】

对于 100 % 100\% 100% 的数据, T ≤ 1 0 3 T\le 10^3 T≤103, p ≤ 1 0 7 p\le10^7 p≤107。


1. 解题思路

根据题意,实际上我们要求的就是
2 2 2 ⋯   m o d   p 2^{2^{2\cdots}} \bmod p 222⋯modp

这样无限个 2 2 2 次幂模 p p p 最终等于多少。由于有无数个 2 2 2,显然指数 2 2 ⋯ > = φ ( p ) 2^{2\cdots} >= \varphi(p) 22⋯>=φ(p),我们可以采用欧拉降幂,因此等于计算
2 ( 2 2 ⋯   m o d   φ ( p ) + φ ( p ) )   m o d   p 2^{(2^{2\cdots} \bmod \varphi(p) + \varphi(p))} \bmod p 2(22⋯modφ(p)+φ(p))modp

显然这里需要用到递归,每一次的递归都需要求模数的欧拉函数,因此需要提前打表,递归终止条件为 p = 1 p = 1 p=1,此时式子的结果为 0 0 0。


2. 代码实现

cpp 复制代码
#include<iostream>

using namespace std;

typedef long long LL;

const int N = 1e7 + 10;
int p[N], phi[N];
bool vis[N];
int cnt;

// 线性筛打表欧拉函数
void get_phi(int n)
{
    phi[1] = 1;
    for(LL i = 2; i <= n; i++)
    {
        if(!vis[i])
        {
            p[cnt++] = i;
            phi[i] = i - 1;
        }
        for(LL j = 0; i * p[j] <= n; j++)
        {
            LL x = i * p[j];
            vis[x] = true;
            if(i % p[j] == 0)
            {
                phi[x] = phi[i] * p[j];
                break;
            }
            else
            {
                phi[x] =  phi[i] * (p[j] - 1);
            }
        }
    }
}

// 快速幂
LL qpow(LL a, LL n, LL p)
{
    LL ret = 1;
    while(n)
    {
        if(n & 1) ret = ret * a % p;
        n >>= 1;
        a = a * a % p;
    }
    return ret;
}

// 递归求解结果
int dfs(int p)
{
    if(p == 1) return 0;
    else return qpow(2, dfs(phi[p]) + phi[p], p);
}

int main()
{
    get_phi(1e7);
    
    int t, p;
    cin >> t;
    while(t--)
    {
        cin >> p;
        int ans = dfs(p);
        cout << ans << endl;
    }

    return 0;
}
相关推荐
徐同保3 小时前
tailwindcss使用@apply指令定义自己的样式
1024程序员节
SEO-狼术3 小时前
How Users Interact with PDFs
1024程序员节
Yupureki3 小时前
从零开始的C++学习生活 14:map/set的使用和封装
c语言·数据结构·c++·学习·visual studio·1024程序员节
盼小辉丶3 小时前
视觉Transformer实战 | Transformer详解与实现
pytorch·深度学习·transformer·1024程序员节
你的电影很有趣3 小时前
lesson77:Vue组件开发指南:从基础使用到高级通信
javascript·vue.js·1024程序员节
zhangzhangkeji3 小时前
UE5 蓝图-12:pawn蓝图,轴映射-鼠标右键,补充轴映射与操作映射的区别。相机的旋转俯仰逻辑,伸缩逻辑,浮点差值函数 FInterpTo;
ue5·1024程序员节
一匹电信狗3 小时前
【LeetCode_876_2.02】快慢指针在链表中的简单应用
c语言·数据结构·c++·算法·leetcode·链表·stl
keineahnung23453 小时前
C++中的Aggregate initialization
c++·1024程序员节
zhangyifang_0093 小时前
【流程引擎】与【规则引擎】
1024程序员节