歐拉定理:若 \(gcd(a,n)=1\),\(a^{\varphi(n)}\equiv 1(mod\ n)\)
設 \(1\sim n-1\) 中與 \(n\) 互素的 \(\varphi(n)\) 個數 \(x_1,x_2,...,x_{\varphi(n)}\in M_1\),那么集合 \(M_1\) 為模 \(n\) 的一個縮系
再設 \(a\cdot x_1,a\cdot x_2,...,a\cdot x_{\varphi(n)}\in M_2\),由於縮系的性質,集合 \(M_2\) 也為模 \(n\) 的縮系
化簡得 \(a^{\varphi(n)}\equiv 1(mod\ n)\)
如何求一個數的歐拉函數?讓我們先證明另一個定理。
定理:\(\varphi(a)=a\cdot (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(1\leq a\leq 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^k\cdot (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)=a\cdot (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^b\equiv a^b(mod\ m)\)
若 \(b\geq \varphi(m)\),\(a^b\equiv 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\n",fast_pow(a,b,m));
return 0;
}
