定义
1
1
1~
N
N
N中与
N
N
N互质的数的个数叫欧拉函数,记为
φ
(
N
)
\varphi(N)
φ(N)
对
N
N
N分解质因数
N
=
p
1
c
1
∗
p
1
c
1
∗
.
.
.
∗
p
k
c
k
N=p_1^{c_1}*p_1^{c_1}*...*p_k^{c_k}
N=p1c1∗p1c1∗...∗pkck
则有
φ
(
N
)
=
N
∗
(
1
−
1
p
1
)
∗
(
1
−
1
p
2
)
∗
.
.
.
∗
(
1
−
1
p
k
)
\varphi(N)=N*(1-\frac{1}{p_1})*(1-\frac{1}{p_2})*...*(1-\frac{1}{p_k})
φ(N)=N∗(1−p11)∗(1−p21)∗...∗(1−pk1)
特别的
φ
(
1
)
=
1
\varphi(1)=1
φ(1)=1
证明
首先显然
1
1
1~
N
N
N中与
N
N
N互质的数就是
1
−
N
1-N
1−N中不与
N
N
N含有相同质因子的数
那么先简单分析
N
N
N只有两个质因子的情况
假设
p
,
q
p,q
p,q为
N
N
N的质因子
那么
1
1
1~
N
N
N中p的倍数有
N
p
\frac{N}{p}
pN个,q的倍数有
N
q
\frac{N}{q}
qN个
我们自然要筛掉这些数
N
−
N
p
−
N
q
N-\frac{N}{p}-\frac{N}{q}
N−pN−qN
但是注意到这里面
p
∗
q
p*q
p∗q的倍数被减了两次
根据容斥原理,当然还要加回来
得
N
−
N
p
−
N
q
+
N
p
q
N-\frac{N}{p}-\frac{N}{q}+\frac{N}{pq}
N−pN−qN+pqN
对这个式子稍作变换
N
−
N
p
−
N
q
+
N
p
q
N-\frac{N}{p}-\frac{N}{q}+\frac{N}{pq}
N−pN−qN+pqN
⇓
\ \ \ \ \ \ \ \ \ \ \ \Downarrow
⇓
N
∗
(
1
−
1
p
−
1
q
+
1
p
q
)
N*(1-\frac{1}{p}-\frac{1}{q}+\frac{1}{pq})
N∗(1−p1−q1+pq1)
⇓
\ \ \ \ \ \ \ \ \ \ \ \Downarrow
⇓
N
∗
(
1
−
1
p
)
∗
(
1
−
1
q
)
N*(1-\frac{1}{p})*(1-\frac{1}{q})
N∗(1−p1)∗(1−q1)
只有两个质因数的情况证毕
到这里再用数学归纳法就可以拓展出上述得式子了
实现
根据上述函数定义式
可以得到一个在分解质因数时同时求解单个欧拉函数的方法
时间复杂度为
O
(
N
)
O(\sqrt{N})
O(N)
int phi(int x)
{
int res=x;
for(int i=2;i*i<=x;++i)
{
if(x%i==0)
{
res=res/i*(i-1);
while(x%i==0) x/=i;
}
}
if(x>1) res=res/x*(x-1);
return res;
}
当然我们还可以有递推打表的计算
类似埃式筛法
每枚举到一个质数,就更新他的所有倍数的phi值
复杂度约为
O
(
N
l
o
g
N
)
O(NlogN)
O(NlogN)
void euler(int n)
{
for(int i=1;i<=n;++i) phi[i]=i;
for(int i=2;i<=n;++i)
{
if(phi[i]==i)//发现一个质数
for(int j=i;j<=n;j+=i)//处理("筛")他的倍数
phi[j]=phi[j]/i*(i-1);
}
}
既然有类似埃式筛的递推方法
那么自然也不会少了线性筛
利用线性筛递推求解phi需要用到欧拉函数的两个性质
1.若有
p
∣
N
p\mid N
p∣N,且满足
p
2
∣
N
p^2\mid N
p2∣N,则
φ
(
N
)
=
φ
(
N
/
p
)
∗
p
\varphi(N)=\varphi(N/p)*p
φ(N)=φ(N/p)∗p
2.若有
p
∣
N
p\mid N
p∣N,且一定不满足
p
2
∣
N
p^2\mid N
p2∣N,则
φ
(
N
)
=
φ
(
N
/
p
)
∗
(
p
−
1
)
\varphi(N)=\varphi(N/p)*(p-1)
φ(N)=φ(N/p)∗(p−1)
这两条性质会在接下来给出证明
线性筛中每个合数n只会被他的最小质因子p筛一次
于是我们利用这点从
φ
(
N
/
p
)
\varphi(N/p)
φ(N/p)递推到
φ
(
N
)
\varphi(N)
φ(N)
复杂度为 O ( N ) O(N) O(N)
void Phi(int n)
{
phi[1]=1;
for(int i=2;i<=n;++i)
{
if(!vis[i]) prim[++cnt]=i,phi[i]=i-1;
for(int j=1;j<=cnt;++j)
{
if(i*prim[j]>n) break;
vis[i*prim[j]]=1;
if(i%prim[j]==0){ phi[i*prim[j]]=phi[i]*prim[j]; break;}
else phi[i*prim[j]]=phi[i]*phi[prim[j]];
}
}
}
欧拉函数的性质
1. ∀ N > 1 \forall N>1 ∀N>1, 1 1 1~ N N N中与 N N N互质的数的和为 N ∗ φ ( N ) / 2 N*\varphi(N)/2 N∗φ(N)/2
证明
若有
x
∈
[
1
,
N
]
x\in[1,N]
x∈[1,N]且
g
c
d
(
N
,
x
)
=
1
(
即
N
与
x
互
质
)
gcd(N,x)=1(即N与x互质)
gcd(N,x)=1(即N与x互质)
根据更相减损术有
g
c
d
(
N
,
x
)
=
g
c
d
(
N
,
N
−
x
)
gcd(N,x)=gcd(N,N-x)
gcd(N,x)=gcd(N,N−x)
即
1
1
1~
N
N
N中与
N
N
N互质的数是成对出现的,对称轴就是
N
/
2
N/2
N/2
也就是说
1
1
1~
N
N
N中与
N
N
N互质的数的平均值是
N
/
2
N/2
N/2
而总和就是
N
∗
φ
(
N
)
/
2
N*\varphi(N)/2
N∗φ(N)/2
证毕
2.(1)当
a
,
b
a,b
a,b互质时,有
φ
(
a
∗
b
)
=
φ
(
a
)
∗
φ
(
b
)
\varphi(a*b)=\varphi(a)*\varphi(b)
φ(a∗b)=φ(a)∗φ(b)
(2)对
N
N
N分解质因数
N
=
p
1
c
1
∗
p
1
c
1
∗
.
.
.
∗
p
k
c
k
N=p_1^{c_1}*p_1^{c_1}*...*p_k^{c_k}
N=p1c1∗p1c1∗...∗pkck,则有
φ
(
N
)
=
∏
i
=
1
k
φ
(
p
i
c
i
)
\varphi(N)=\prod_{i=1}^k\varphi(p_i^{c_i})
φ(N)=∏i=1kφ(pici)
证明
这里的两条性质其实是直接应用了积性函数的性质
什么是积性函数
如果当
a
,
b
a,b
a,b互质时,有
f
(
a
∗
b
)
=
f
(
a
)
∗
f
(
b
)
f(a*b)=f(a)*f(b)
f(a∗b)=f(a)∗f(b),则
f
(
x
)
为
积
性
函
数
f(x)为积性函数
f(x)为积性函数
上述(1)是直接应用了定义
而(2)中将N分解质因数,显然分解的每一项都两两互质
根据积性函数定义也不难得出上述式子
3.(1)若有
p
∣
N
p\mid N
p∣N,且满足
p
2
∣
N
p^2\mid N
p2∣N,则
φ
(
N
)
=
φ
(
N
/
p
)
∗
p
\varphi(N)=\varphi(N/p)*p
φ(N)=φ(N/p)∗p
(2)若有
p
∣
N
p\mid N
p∣N,且一定不满足
p
2
∣
N
p^2\mid N
p2∣N,则
φ
(
N
)
=
φ
(
N
/
p
)
∗
(
p
−
1
)
\varphi(N)=\varphi(N/p)*(p-1)
φ(N)=φ(N/p)∗(p−1)
证明
上述(1)中"若有
p
∣
N
p\mid N
p∣N,且满足
p
2
∣
N
p^2\mid N
p2∣N"
说明N和N/p含有相同质因子
我们分析只含有两个质因子p和q的简单情况
φ
(
N
)
=
N
−
N
p
−
N
q
+
N
p
q
\varphi(N)=N-\frac{N}{p}-\frac{N}{q}+\frac{N}{pq}
φ(N)=N−pN−qN+pqN
φ
(
N
/
p
)
=
N
p
−
N
p
2
−
N
p
q
+
N
p
2
q
\varphi(N/p)=\frac{N}{p}-\frac{N}{p^2}-\frac{N}{pq}+\frac{N}{p^2q}
φ(N/p)=pN−p2N−pqN+p2qN
二者相除商为p
用数学归纳法扩展出k个质因子的情况可以得到相同结果
上述(2)中 “若有
p
∣
N
p\mid N
p∣N,且一定不满足
p
2
∣
N
p^2\mid N
p2∣N”
说明
N
N
N和
N
/
p
N/p
N/p一定互质
根据积性函数定义有
φ
(
N
)
=
φ
(
N
/
p
)
∗
φ
(
p
)
\varphi(N)=\varphi(N/p)*\varphi(p)
φ(N)=φ(N/p)∗φ(p)
因为p为素数,所以
φ
(
p
)
=
p
−
1
\varphi(p)=p-1
φ(p)=p−1
得
φ
(
N
)
=
φ
(
N
/
p
)
∗
(
p
−
1
)
\varphi(N)=\varphi(N/p)*(p-1)
φ(N)=φ(N/p)∗(p−1)
证毕
4. ∑ d ∣ n φ ( d ) = n \sum_{d|n}\varphi(d)=n ∑d∣nφ(d)=n
证明
设
f
(
n
)
=
∑
d
∣
n
φ
(
d
)
=
n
f(n)=\sum_{d|n}\varphi(d)=n
f(n)=∑d∣nφ(d)=n
若有n,m互质,那么
f
(
n
m
)
=
∑
d
∣
n
m
φ
(
d
)
=
∑
d
∣
n
φ
(
d
)
∗
∑
d
∣
m
φ
(
d
)
f(nm)=\sum_{d|nm}\varphi(d)=\sum_{d|n}\varphi(d)*\sum_{d|m}\varphi(d)
f(nm)=∑d∣nmφ(d)=∑d∣nφ(d)∗∑d∣mφ(d)
可得
f
(
n
)
f(n)
f(n)为积性函数
对于n的某个质因子
f
(
p
k
)
=
∑
d
∣
p
k
φ
(
d
)
=
φ
(
1
)
+
φ
(
p
)
+
φ
(
p
2
)
+
.
.
.
+
φ
(
p
k
)
f(p^k)=\sum_{d|p^k}\varphi(d)=\varphi(1)+\varphi(p)+\varphi(p^2)+...+\varphi(p^k)
f(pk)=∑d∣pkφ(d)=φ(1)+φ(p)+φ(p2)+...+φ(pk)
由上述3.(1)知该式为一个等比数列+1,公比为p
更具等比数列求和公式得
f
(
p
k
)
=
p
k
f(p^k)=p^k
f(pk)=pk
所以
f
(
n
)
=
∏
i
=
1
k
f
(
p
k
)
=
∏
i
=
1
k
p
k
=
n
f(n)=\prod_{i=1}^{k}f(p^k)=\prod_{i=1}^kp^k=n
f(n)=∏i=1kf(pk)=∏i=1kpk=n
证毕
欧拉定理
定理:若正整数 a , n a,n a,n互质,则有 a φ ( n ) ≡ 1 ( m o d n ) a^{\varphi(n)}\equiv 1(\mod n) aφ(n)≡1(modn)
推论:若正整数 a , n a,n a,n互质,则对于任意正整数b,有 a b ≡ a b m o d φ ( n ) ( m o d n ) a^b\equiv a^{b\mod \varphi(n)}(\mod n) ab≡abmodφ(n)(modn)
扩展欧拉定理:
a
,
n
∈
Z
a,n\in Z
a,n∈Z,则
a
b
a^b
ab
{
a
b
,
b
<
φ
(
n
)
a
b
m
o
d
φ
(
n
)
+
φ
(
n
)
,
b
>
=
φ
(
n
)
\left\{\begin{aligned}a^b,b<\varphi(n)\\ a^{b\mod\varphi(n)+\varphi(n) },b>=\varphi(n)\end{aligned}\right.
{ab,b<φ(n)abmodφ(n)+φ(n),b>=φ(n)
m
o
d
n
\mod n
modn
证明略
应用
给定三个正整数
a
,
m
,
b
a,m,b
a,m,b,求
a
b
m
o
d
m
a^b\mod m
abmodm
1
≤
a
≤
1
0
9
,
1
≤
b
≤
1
0
20000000
,
1
≤
m
≤
1
0
6
1≤a≤10^{9},1≤b≤10^{20000000},1≤m≤10^6
1≤a≤109,1≤b≤1020000000,1≤m≤106
直接套用上述定理
#include<iostream>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long lt;
const int maxn=100010;
lt a,m,phi,rem;
lt read()
{
lt x=0;
char ss=getchar();
while(ss<'0'||ss>'9') ss=getchar();
while(ss>='0'&&ss<='9'){
x=x*10+ss-'0';ss=getchar();
if(x>=phi) rem=1,x%=phi;
}
return x;
}
lt calc(lt x)
{
lt res=x;
for(int i=2;i*i<=x;++i)
{
if(x%i==0)
{
res=res/i*(i-1);
while(x%i==0) x/=i;
}
}
if(x>1) res=res/x*(x-1);
return res;
}
lt qpow(lt aa,lt k)
{
lt res=1;
while(k){
if(k&1) res=(res*aa)%m;
aa=(aa*aa)%m; k>>=1;
}
return res;
}
int main()
{
scanf("%d%d",&a,&m);
phi=calc(m);
lt b=read();
if(rem) b+=phi;
printf("%d",qpow(a,b));
return 0;
}