题解:P5091 【模板】扩展欧拉定理
Yi_chen123 · · 题解
更新于 2025/9/9:增加了欧拉函数
一、欧拉函数
表示:
如何计算欧拉函数?
方法一:暴力法
暴力计算
时间复杂度
方法二:质因数分解法
我们假设
其中
那么:
代码:
int phi(int x){
int ans = x; //初始化
for(int i = 2; i * i <= x; ++i){
if(x % i == 0){ //存在该质因数
while(x % i == 0) x /= i; //将所有质因数给除完
ans /= i;
ans *= (i - 1); //等价于乘上 (i - 1) / i,也就是计算上式的其中一项
}
}
if(x > 1)
ans /= x, ans *= (x - 1); //出现剩余特判
return ans;
}
时间复杂度
::::success[正确性证明]{open}
引理:
\varphi(p^t) = p^{t-1}\times (p-1) 。
由欧拉函数的定义,及因式分解易证。
我们令
根据欧拉函数的积性,可以得到
根据引理,变形上式得
由于
由乘法结合律得
将原假设代入得
原命题得证。 ::::
二、欧拉定理
内容
若
证明
- 我们不妨假设
r_1,r_2,\cdots,r_{\varphi(m)} 是模m 意义下的一个简化剩余系。也就是说,对于任意的i ,有\gcd(r_i,m) = 1 ;对于任意的i\ne j ,有r_i\not\equiv r_j \pmod m 。 - 将每一个元素都乘上
a ,由于\gcd(a,m) = 1 ,所以易证a\cdot r_1,a\cdot r_2,\cdots,a\cdot r_{\varphi(m)} 也是模m 的简化剩余系。(因为如果a\cdot r_i \equiv a\cdot r_j \pmod m ,那么由于a,m 互质,消掉两边的a 会得到r_i \equiv r_j ,与原假设矛盾) - 这个时候,将两个序列中的元素分别相乘,不难发现它们模
m 意义下是同余的,即:\prod_{i=1}^{\varphi(m)} r_i \equiv \prod_{i=1}^{\varphi(m)} (a\cdot r_i) \pmod m - 将同余号右边的
\varphi(m) 个a 从求积符号中提出来,得:\prod_{i=1}^{\varphi(m)} r_i \equiv a^{\varphi(m)}\prod_{i=1}^{\varphi(m)} r_i \pmod m - 因为
\prod r_i 是和m 互质的,因此可以从同余式中消掉。故:1 \equiv a^{\varphi(m)} \pmod m
原命题得证。
三、扩展欧拉定理
内容
设
证明
分多种情况讨论。
情况一:b < \varphi(m)
如果不会证这个建议重修幼儿园数学(不是)。
情况二:b > \varphi(m),\gcd(a,m) = 1
套普通欧拉定理就行,你们自己证吧我跑了。
接下来的两种情况,我们需要对
现在问题等价于:
显然这个时候要么
情况三:\gcd(m,p_i) = 1
仍然是套普通欧拉定理所以我再跑。
情况四:m\ |\ p_i
不水了不水了,讲正经的。
首先需要插播一条欧拉函数的性质:若
由于:
故:
进一步得出:
因为
两个同余式的左边一坨都和
由于
综上,原定理成立。
四、解题思路
套公式。
五、代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int qpow(int a, int b, int m){ //快速幂
int base = a, ans = 1;
while(b > 0){
if(b & 1) ans *= base, ans %= m;
base = base * base % m, b >>= 1;
}
return ans;
}
int phi(int x){ //欧拉函数计算
int ans = x;
for(int i = 2; i * i <= x; ++i){
if(x % i == 0){
while(x % i == 0) x /= i;
ans /= i;
ans *= (i - 1);
}
}
if(x > 1)
ans /= x, ans *= (x - 1);
return ans;
}
signed main(){
int a, m, b = 0; cin >> a >> m;
int ph = phi(m); char c = getchar();
while(!isdigit(c)) c = getchar();
bool flag = false;
while(isdigit(c)){ //边读入边取模,高精度再见!
b = (b << 3) + (b << 1) + (c ^ '0');
if(b >= ph) flag = true, b %= ph;
c = getchar();
}
if(flag) b += ph; //需要特判指数上是否加上 phi(m)
cout << qpow(a, b, m);
return 0;
}
六、时空复杂度分析
- 时间复杂度:
\Theta (\log(b \bmod \varphi (m))) - 证明:代码中调用了一次指数为
b \bmod \varphi(m) 或者b\bmod \varphi(m) + \varphi(m) 的快速幂,由于其复杂度为\Theta(n) ,其中n 为指数,故复杂度分析正确,且足以通过本题。
- 证明:代码中调用了一次指数为
- 空间复杂度:
\Theta(1) - 证明:只使用了常数个变量。