136 lines
4.7 KiB
Markdown
136 lines
4.7 KiB
Markdown
## 数论 欧拉降幂+费马小定理+指数循环节+幂塔
|
||
|
||
**[姊妹文章](https://www.cnblogs.com/littlehb/p/15361630.html)**
|
||
|
||
### 一、指数循环节
|
||
|
||
**题目大意**:求$2^a\%1000000007$,$1 \leq a \leq 10^{100000}$。
|
||
|
||
和队友一直怼 **快速幂**。然后$T$了。后来发现这个余数应该是循环的,我当时认为循环节是$1000000007$。后来才知道发现是$1000000006$。
|
||
让我们来复习一下费马小定理:
|
||
$$\large a^{p-1} \equiv 1 \ (mod \ p) \ gcd(a,p)=1$$
|
||
|
||
> **举例子**:
|
||
> 取$p=7,a=3$,$gcd(3,7)=1$,可以使用费马小定理:
|
||
$3^6 ≡ 1 (mod \ 7)$
|
||
这有啥用呢?比如让我们求$3^{128}\%7$的值,我们就可以用:
|
||
$3^{128} \%7=3^{21*6+2}\%7=(3^6)^{21}\%7\times 3^2\%7=\underbrace{3^6\%7\times 3^6\%7\times ...\times 3^6\%7}_{\text{21个}}\times 3^2\%7 =\underbrace{1\times 1\times ...\times 1}_{\text{21个}}\times 3^2\%7 =9 \% 7=2$
|
||
验证:我们可以用微软的$bing$直接输入$3^{128}\%7$就可以得到答案。
|
||

|
||
|
||
|
||
$2$与$1000000007$互质,$2 ^ 0 = 2 ^ {p-1}$ 所以循环节为$p-1=1000000006$。
|
||
|
||
$\therefore 2 ^ a \%1000000007 = 2 ^ {a \%1000000006} \%1000000007$。
|
||
|
||
|
||
|
||
当然还可以用 **欧拉降幂**:
|
||

|
||
|
||
结果不出我所料:$1000000007$的欧拉函数就是$1000000006$。
|
||
> **注**:最后这句肯定是废话了,因为$1000000007$是质数嘛,$\phi(1000000007)$当然是$1000000006$了,这还用说啊~
|
||
|
||
### 二、幂塔的计算 (欧拉降幂)
|
||
形如以下式子的东西叫做 **幂塔**:
|
||
$$\large a^{a^{a^{a^...}}}$$
|
||
|
||
**题目**
|
||
给定$a,n,m$,计算$a$的$n$层幂塔对$m$取模后的结果。
|
||
$(1<=a,n,m<=1e6)$
|
||
|
||
**解法**
|
||

|
||
运用欧拉降幂递归求解即可。
|
||
|
||
**具体过程**:
|
||
|
||
定义的递归函数形式:$f(a,n,m)$,表示$a$的$n$层幂塔对$m$取模后的结果。
|
||
|
||
- 首先是对边界情况的判断(递归结束条件)
|
||
- 当$m=1$时,$f(a,n,m)=0$.
|
||
> **解释**:因为任意整数对$1$取模都是$0$,表示任意整数都能被$1$整除,没有留下余数。
|
||
|
||
- 当$n<=1$时,$f(a,n,m)=qmi(a,n,m)$.
|
||
> **解释**:$n=1$也就是$1$层,那算就完了
|
||
|
||
- 欧拉降幂公式的$3$种情况
|
||
|
||
- 当$gcd(a,m)=1$时
|
||
$\large f(a,n,m)=pow(a,f(a,n−1,φ(m)),m)$
|
||
> <font color='red' size=3><b>理解</b></font>:
|
||
$a^b \equiv a^{b \ mod \ φ(m)},gcd(a,m)=1$
|
||
我们看到:$g(a,n)=a^{a^{a^...}}$就是$n$层幂塔,如果把最底下的那个$a$去掉,剩下的就是$n-1$层幂塔,即$b=g(a,n-1)$
|
||
根据降幂公式,在取模的场景下,$b$是可以变形为 $b \mod \ φ(m)$
|
||
即$b=f(a,n-1,φ(m))$
|
||
|
||
- 当$gcd(a,m)\neq 1$ 且 $a$的$n−1$层幂塔$ ≥ φ(m)$时
|
||
$\large f(a,n,m)=pow(a,f(a,n−1,φ(m))+φ(m),m)$
|
||
<br>
|
||
|
||
- 当$gcd(a,m)\neq 1$ 且 $a$的$n−1$层幂塔$< φ(m)$时
|
||
$\large f(a,n,m)=pow(a,f(a,n−1,φ(m)),m)$
|
||
|
||
```cpp {.line-numbers}
|
||
#include <bits/stdc++.h>
|
||
using namespace std;
|
||
const int N = 1e5 + 10;
|
||
#define int long long
|
||
#define endl '\n'
|
||
|
||
// 快速幂
|
||
int qmi(int a, int b, int p) {
|
||
int res = 1;
|
||
while (b) {
|
||
if (b & 1) res = res * a % p;
|
||
b >>= 1;
|
||
a = a * a % p;
|
||
}
|
||
return res;
|
||
}
|
||
|
||
// 求单个数的欧拉函数值
|
||
int phi(int x) {
|
||
int res = x;
|
||
for (int i = 2; i <= x / i; 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;
|
||
}
|
||
|
||
// 判断n层幂塔指数是否>=phi
|
||
bool check(int a, int n, int phi) {
|
||
if (n == 0) return phi <= 1; // 0层幂塔是1
|
||
if (a >= phi) return true; // 底数a>=phi,那么它的幂塔一定>=phi
|
||
return check(a, n - 1, log(phi) / log(a)); // 取对数,消去一层,继续判断
|
||
}
|
||
|
||
// 计算n层幂塔: a^a^a^a..^a (mod m)
|
||
// 其中共有n个a
|
||
int f(int a, int n, int m) {
|
||
if (m == 1) return 0; // 对1取模,恒为0
|
||
if (n <= 1) return qmi(a, n, m);
|
||
int p = phi(m);
|
||
// 互质
|
||
if (__gcd(a, m) == 1) return qmi(a, f(a, n - 1, p), m);
|
||
// 不互质
|
||
if (check(a, n - 1, p))
|
||
return qmi(a, f(a, n - 1, p) + p, m); // a的指数>=phi
|
||
|
||
return qmi(a, f(a, n - 1, p), m); // a的指数<phi, 所以改成对phi取模对答案无影响
|
||
}
|
||
|
||
signed main() {
|
||
int T;
|
||
cin >> T;
|
||
while (T--) {
|
||
int a, n, m;
|
||
cin >> a >> n >> m;
|
||
cout << f(a, n, m) << endl;
|
||
}
|
||
}
|
||
|
||
``` |