专栏文章

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

P5091题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@mior6aa7
此快照首次捕获于
2025/12/02 23:48
3 个月前
此快照最后确认于
2025/12/02 23:48
3 个月前
查看原文

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

欧拉函数 φ(n)\varphi(n)

欧拉函数定义

欧拉函数(Euler's totient function),即 φ(n)\varphi(n),表示的是小于等于 nn 并且 nn 互质的正整数的个数。
形式化的讲,若集合 A={x gcd(x,n)=1,x[1,n]}A=\{ x\ | \gcd(x,n)=1,x \in [1,n] \},则 φ(n)=card(A)\varphi(n)=\operatorname{card}(A),其中,card(A)\operatorname{card}(A) 表示有限集 AA 中的元素个数(见人教 20192019 版数学必修一第 1515 页)。
举个例子,φ(7)=6\varphi(7)=6φ(10)=4\varphi(10)=4

欧拉函数实现

方法一:暴力

循环 xx11nn,对于每一个 xx,求 gcd(x,n)\gcd(x,n) 是否为 11φ(n)\varphi(n)gcd(x,n)\gcd(x,n)11 的次数。
gcd\gcd 函数的时间复杂度为 Θ(logn)\Theta(\log n),由于重复 nn 次,所以整体时间复杂度为 Θ(nlogn)\Theta(n \log n)

方法二:质因数分解

n=p1a1×p2a2×p3a3××pkak,piprime  and  tiN+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_+}
由唯一分解定理,有
φ(n)=ni=1k(11pi)=ni=1kpi1pi\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}
证明如下:
代码如下:
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;
}
时间复杂度 Θ(n)\Theta(\sqrt{n})
欢迎大家在练习题目中提交。

费马小定理

费马小定理是欧拉定理的一个推论。
pp 为质数,gcd(a,p)=1\gcd(a,p)=1,且 a,pZa,p \in \mathbb{Z},则
ap11(modp)a^{p-1} \equiv 1(\operatorname{mod} p) ababmod(p1)(modp)\therefore a^b \equiv a^{b \operatorname{mod} (p-1)}(\operatorname{mod} p)
证明见 OI-Wiki

欧拉定理

a,nZa,n \in \mathbb{Z},且 gcd(a,n)=1\gcd(a,n)=1 时有:
aφ(n)1(modn)a^{\varphi(n)} \equiv 1(\operatorname{mod} 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; } ``````

评论

1 条评论,欢迎与作者交流。

正在加载评论...