题解 P5091 【【模板】欧拉定理】

欧拉定理:若 \(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\) 的缩系

\[\Longrightarrow a\cdot x_1\cdot a\cdot x_2\cdot ...\cdot a\cdot x_{\varphi(n)}\equiv x_1,x_2,...,x_{\varphi(n)}(mod\ 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\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;
}
posted @ 2018-12-11 13:33  Owen_codeisking  阅读(1448)  评论(1编辑  收藏  举报