欧拉定理:若 (gcd(a,n)=1),(a^{varphi(n)}equiv 1(mod n))
设 (1sim n-1) 中与 (n) 互素的 (varphi(n)) 个数 (x_1,x_2,...,x_{varphi(n)}in M_1),那么集合 (M_1) 为模 (n) 的一个缩系
再设 (acdot x_1,acdot x_2,...,acdot x_{varphi(n)}in M_2),由于缩系的性质,集合 (M_2) 也为模 (n) 的缩系
化简得 (a^{varphi(n)}equiv 1(mod n))
如何求一个数的欧拉函数?让我们先证明另一个定理。
定理:(varphi(a)=acdot (1-frac {1}{p_1})cdot (1-frac {1}{p_2})cdot ...cdot (1-frac {1}{p_n}))
-
当 (a=p) 时,即 (a) 是素数,(varphi(a)=a-1)
-
当 (a=p^k(k>1)) 时,即 (a) 是一个素数幂,先考虑与 (p^k) 不互素的数 (a(1leq aleq p^k)),(p^k) 仅有因子 (p),所以 (p|a) 必定成立。所以 (a) 的值可以有 (p,2p,3p,...,p^{k-1}cdot p),显然个数为 (p^{k-1}) 个。又知小于等于 (a) 的正整数总数为 (p^k) 个,所以 (varphi(a)=p^k-p^{k-1}=p^kcdot (1-frac {1}{p}))
-
当 (a) 为合数时,可表示为 (a=p_1^{k_1}cdot p_2^{k_2}cdot ...cdot p_n^{k_n}),是多个素数幂的积。由 (varphi(nm)=varphi(n)cdot varphi(m)) 得 $$varphi(a)=varphi(p_1^{k_1})cdot varphi(p_2^{k_2})cdot ...cdot varphi(p_n^{k_n})=p_1^{k_1}cdot (1-frac{1}{p_1})cdot p_2^{k_2}cdot (1-frac {1}{p_2})cdot ...cdot p_n^{k_n}cdot (1-frac {1}{p_n})$$ 合并所有 (p_i^{k_i}) 等于 (a),证得 (varphi(a)=acdot (1-frac {1}{p_1})cdot (1-frac {1}{p_2})cdot ...cdot (1-frac {1}{p_n}))
不少证明 (varphi(nm)=varphi(n)cdot varphi(m)) 都是一句话显然,所以有兴趣的话可以证明上述性质。
然后根据引理,可以在 (O(sqrt{n})) 的时间内求出一个数的欧拉函数,这一般在不能线性筛出 (varphi) 函数时使用。
扩展欧拉定理:
若 (b<varphi(m)),(a^bequiv a^b(mod m))
若 (bgeq varphi(m)),(a^bequiv a^{b mod varphi(m)+varphi(m)}(mod m))
(b) 的指数部分可以边乘边模,最后对 (a^b) 线性求或者快速幂即可
(Code Below:)
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll a,m,b;
inline ll read(ll m){
register ll x=0,f=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)){
x=x*10+ch-'0';
if(x>=m) f=1;
x%=m;ch=getchar();
}
return x+(f==1?m:0);
}
ll phi(ll n){
ll ans=n,m=sqrt(n);
for(ll i=2;i<=m;i++){
if(n%i==0){
ans=ans/i*(i-1);
while(n%i==0) n/=i;
}
}
if(n>1) ans=ans/n*(n-1);
return ans;
}
ll fast_pow(ll a,ll b,ll p){
ll ret=1;
for(;b;b>>=1,a=a*a%p)
if(b&1) ret=ret*a%p;
return ret;
}
int main()
{
scanf("%lld%lld",&a,&m);
b=read(phi(m));
printf("%lld
",fast_pow(a,b,m));
return 0;
}