题解:P5091 【模板】扩展欧拉定理

· · 题解

题解:P5091 【模板】扩展欧拉定理

题目传送门

欧拉函数 \varphi(n)

欧拉函数定义

欧拉函数(Euler's totient function),即 \varphi(n),表示的是小于等于 n 并且 n 互质的正整数的个数。

形式化的讲,若集合 A=\{ x\ | \gcd(x,n)=1,x \in [1,n] \},则 \varphi(n)=\operatorname{card}(A),其中,\operatorname{card}(A) 表示有限集 A 中的元素个数(见人教 2019 版数学必修一第 15 页)。

举个例子,\varphi(7)=6\varphi(10)=4

欧拉函数实现

练习题目

方法一:暴力

循环 x1n,对于每一个 x,求 \gcd(x,n) 是否为 1\varphi(n)\gcd(x,n)1 的次数。

#### 方法二:质因数分解 若 $$ n={p_1}^{a_1}\times {p_2}^{a_2}\times {p_3}^{a_3}\times \cdots \times {p_k}^{a_k},\forall p_i \in \text{prime}\ \ \text{and} \ \ \forall t_i \in \mathbb{N_+} $$ 由唯一分解定理,有 $$ \varphi(n)=n \prod_{i=1}^{k} \big \lparen 1-\dfrac{1}{p_i} \big \rparen =n \prod_{i=1}^{k} \dfrac{p_i-1}{p_i} $$ [证明](https://oi-wiki.org/math/number-theory/euler-totient/#性质)如下: ![](https://cdn.luogu.com.cn/upload/image_hosting/ny4oqlrp.png) 代码如下: ```cpp ll phi(ll n){ ll ans=n; for(register int i=2;i*i<=n;i++){ if(!(n%i)){ while(!(n%i))n/=i; ans/=i; ans*=(i-1); } } if(n>1){ ans/=n,ans*=(n-1); } return ans; } `````` 时间复杂度 $\Theta(\sqrt{n})$。 欢迎大家在[练习题目](https://www.luogu.com.cn/problem/U587132)中提交。 ## [费马小定理](https://oi-wiki.org/math/number-theory/fermat/#费马小定理) 费马小定理是欧拉定理的一个推论。 若 $p$ 为质数,$\gcd(a,p)=1$,且 $a,p \in \mathbb{Z}$,则 $$ a^{p-1} \equiv 1(\operatorname{mod} p) $$ $$ \therefore a^b \equiv a^{b \operatorname{mod} (p-1)}(\operatorname{mod} p) $$ 证明见 [OI-Wiki](https://oi-wiki.org/math/number-theory/fermat/#证明)。 ## [欧拉定理](https://oi-wiki.org/math/number-theory/fermat/#欧拉定理) 当 $a,n \in \mathbb{Z}$,且 $\gcd(a,n)=1$ 时有: $$ a^{\varphi(n)} \equiv 1(\operatorname{mod} n)。 $$ 所以 $$a^b \equiv a^{b \operatorname{mod} \varphi(n)} (\operatorname{mod} n) $$ 证明见 [OI-Wiki](https://oi-wiki.org/math/number-theory/fermat/#证明_1)。 当 $n \in \text{prime}$ 时,$\varphi(n)=n-1$,有 $$ a^b \equiv a^{b \operatorname{mod} (n-1)}(\operatorname{mod} n) $$ 即费马小定理,所以费马小定理是欧拉定理的一个推论。 ## [拓展欧拉定理](https://oi-wiki.org/math/number-theory/fermat/#扩展欧拉定理) 本题重点。 $$ a^b \equiv \left\{ \begin{array}{rcl} a^{b \operatorname{mod} \varphi(n)}, & \gcd(a,n)=1,\\ a^b & \gcd(a,n) \neq 1, &b<\varphi(n), \\ a^{(b \operatorname{mod} \varphi(n))+\varphi(n)}& \gcd(a,n) \neq 1,&b \geq \varphi(n), \end{array}\right. \lparen \operatorname{mod} n \rparen. $$ 证明见 [OI-Wiki](https://oi-wiki.org/math/number-theory/fermat/#证明_2) 现在,前置知识讲完了,我们来梳理一下思路: ![](https://cdn.luogu.com.cn/upload/image_hosting/x2t2f7js.png) ## 代码(共建美好洛谷,请勿抄袭) 注释代码是我的部分数论模版,供选用。 ```cpp #include<bits/stdc++.h> using namespace std; const unsigned long long N=6e5+5,M=6e5+5,prime=233317,Mod=212370440129904639,base=131; typedef unsigned long long ll; //#define int ll ll n,p,a,b,m,mod; #define inf 0x3f3f3f3f #define mark 20250723222447 ll gcd(int x,int y){ int i,j; if(x==0)return y; if(y==0)return x; for(i=0;(x&1)==0;i++)x>>=1; for(j=0;(y&1)==0;j++)y>>=1; if(j<i)i=j; while(1){ if(x<y)x^=y,y^=x,x^=y; if(0==(x-=y))return y<<i; while(0==(x&1))x>>=1; } } //ll x,y; //inline void exgcd(ll a,ll b){ // if(!b){ // x=1,y=0; // return; // } // exgcd(b,a%b); // ll k; // k=x;x=y; // y=k-a/b*y; //} ll fpm(ll x,ll power,ll mod){//快速幂 x%=mod; ll ans=1; for(;power;power>>=1,(x*=x)%=mod) if(power&1)(ans*=x)%=mod; return ans; } //ll inv[3000005]; //ll niyuan(ll n,ll p,ll mod){ // inv[1]=1; // for(register int i=2;i<=n;i++){ // inv[i]=(p-p/i)*inv[p%i]%mod; // } // return inv[n]; //} //ll niyuan2(ll a,ll b){ // exgcd(a,b); // x=(x+b)%b; // return x; //} bool flag; ll getll(ll mod){//读入部分 ll res=0;char ch; while(!(ch>='0' && ch<='9') && ch!=EOF){ ch=getchar(); } while((ch>='0' && ch<='9')){ res=(res<<3)+(res<<1)+(ch-'0');//等价于 res=res*10+(ch-'0') if(res>=mod)flag=true; res%=mod; ch=getchar(); } return res; } ll phi(ll n){//欧拉函数 ll ans=n; for(register int i=2;i*i<=n;i++){ if(!(n%i)){ while(!(n%i))n/=i; ans/=i; ans*=(i-1); } } if(n>1){ ans/=n,ans*=(n-1); } return ans; } ll phm=0; ll exeut(ll a,ll b,ll m){//Extended Euler's theorem的自创缩写qwq ll phm=phi(m); if(gcd(a,m)==1)return fpm(a,b%phm,m); if(!flag)return fpm(a,b,m); else return fpm(a,(b%phm)+phm,m); } signed main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); a=getll(1e10);m=getll(1e10); phm=phi(m); b=getll(phm); cout<<exeut(a,b,m); return 0; } ``````