欧拉函数
目录:
1.欧拉函数的定义
2.欧拉函数的通式
3.欧拉函数的性质
4.欧拉函数的单个求法
5.欧拉函数的打表求法
6.例题
1.欧拉函数的定义
欧拉函数,记作 φ ( n ) \varphi(n) φ(n),是闭区间 [ 1 , n ] [1,n] [1,n]中与n互质的数的个数,例如, φ ( 12 ) = 4 \varphi(12)=4 φ(12)=4,因为1,5,7,11与12互质
2.欧拉函数的通式
φ ( x ) = x ( 1 − 1 p 1 ) ( 1 − 1 p 2 ) … … ( 1 − 1 p n ) , x ≠ 1 \varphi(x)=x(1-{1\over p_1})(1-{1\over p_2})……(1-{1\over p_n}),x\not=1 φ(x)=x(1−p11)(1−p21)……(1−pn1),x=1
φ ( x ) = 1 , x = 1 \varphi(x)=1,\ x=1 φ(x)=1, x=1
其中, p i p_i pi表示x用唯一分解定理分解后的所有质因数
其实很好理解,因为如果两个数互质,说明它们没有共同的质因数, [ 1 , n ] [1,n] [1,n]内共有n个数, ( 1 − 1 p k ) (1-{1\over p_k}) (1−pk1)表示[1,n]内没有 p k p_k pk这个质因数的数的比例,例如12,它的质因数是2,3,则 ( 1 − 1 2 ) (1-{1\over 2}) (1−21)表示有一半的数都是没有2这个质因数的, ( 1 − 1 3 ) (1-{1\over 3}) (1−31)表示有三分之二的数都是没有3这个质因数的,这样不断筛选下来最后剩下的个数就是与n互质的个数了.(也可以用容斥原理进行证明)
3.欧拉函数的性质
以下性质通过上述对通式的解释都很好证明 ?
-
(一)对于任何质数 x x x, φ ( x ) = x − 1 \varphi(x)=x-1 φ(x)=x−1
-
(二)如果 x x x, y y y互质, φ ( x y ) = φ ( x ) φ ( y ) \varphi(xy)=\varphi(x)\varphi(y) φ(xy)=φ(x)φ(y),满足积性函数的性质
-
(三)如果 x x x是奇数, φ ( 2 x ) = φ ( x ) \varphi(2x)=\varphi(x) φ(2x)=φ(x)
-
(四)如果 x x x是质数,对于任意正整数 a a a,都有: φ ( x a ) = x a − x a − 1 = ( x − 1 ) x a − 1 \varphi(x^a)=x^a-x^{a-1}=(x-1)x^{a-1} φ(xa)=xa−xa−1=(x−1)xa−1
-
(五)如果 x > 2 x>2 x>2,则 φ ( x ) \varphi(x) φ(x)是偶数
-
(六) [ 1 , x ] [1,x] [1,x]中与 x x x互质的所有数的和为 ( φ ( x ) ∗ x ) 2 (\varphi(x)*x)\over 2 2(φ(x)∗x)
4.欧拉函数的单个求法
利用通式的含义,筛出质因子并不断作乘法
int phi(int n)
{
int res=n;
for (int i=2;i*i<=n;i++)
{
if (n%i==0)
{
res=res/i*(i-1);//先进行除法防止中间数据的溢出
while(n%i==0)n/=i;
}
}
if (n>1)res=res/n*(n-1);
return res;
}
5.欧拉函数的打表求法
1.如果用求n次的单个欧拉函数的话时间复杂度是 O ( n n ) O(n\sqrt{n}) O(nn),不是很优的算法
2.下面这个算法的时间复杂度 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))也蛮好理解的,当一个数的phi[i]=i时,说明其在之前的循环过程中尚未发现它的质因子,就从它开始把它的倍数都进行乘法处理
3 还有一种线性筛法,时间复杂度是 O ( n ) O(n) O(n)的
(一)递归打表
const int maxn=3e6+7;
int phi[maxn];
void phi_init()
{
phi[1]=1;
repp(i,2,maxn)phi[i]=i;
repp(i,2,maxn)
{
if (phi[i]==i)
{
for (int j=i;j<maxn;j+=i)
{
phi[j]=phi[j]/i*(i-1);
}
}
}
}
(二)线性筛打表
当 p 是 质 数 { 1. φ ( i p ) = φ ( i ) ∗ p , i % p = 0 2. φ ( i p ) = φ ( i ) φ ( p ) , i , p 互 质 当p是质数 \begin{cases} 1.\varphi(ip)=\varphi(i)*p,i\%p=0\\ 2.\varphi(ip)=\varphi(i)\varphi(p),i,p互质\\ \end{cases} 当p是质数{1.φ(ip)=φ(i)∗p,i%p=02.φ(ip)=φ(i)φ(p),i,p互质
第一条证明:
设
i
p
=
p
1
k
1
p
2
k
2
p
3
k
3
…
…
p
n
k
n
ip=p_1^{k_1}p_2^{k_2}p_3^{k_3}……p_n^{k_n}
ip=p1k1p2k2p3k3……pnkn,由于
i
%
p
=
=
0
i\%p==0
i%p==0,所有p的质因子都属于
p
i
(
1
<
=
i
<
=
n
)
集
合
内
p_i(1<=i<=n)集合内
pi(1<=i<=n)集合内,根据欧拉函数的通式可得:
φ
(
i
p
)
=
i
p
(
1
−
1
p
1
)
(
1
−
1
p
2
)
(
1
−
1
p
3
)
…
…
(
1
−
1
p
n
)
\varphi(ip)=ip(1-{1\over p_1})(1-{1\over p_2})(1-{1\over p_3})……(1-{1\over p_n})
φ(ip)=ip(1−p11)(1−p21)(1−p31)……(1−pn1),可得
i
(
1
−
1
p
1
)
(
1
−
1
p
2
)
(
1
−
1
p
3
)
…
…
(
1
−
1
p
n
)
=
φ
(
i
)
i(1-{1\over p_1})(1-{1\over p_2})(1-{1\over p_3})……(1-{1\over p_n})=\varphi(i)
i(1−p11)(1−p21)(1−p31)……(1−pn1)=φ(i),证毕
第二条证明:见博客?
int phi[maxn];
bool prime[maxn];//prime[i]=true表示i是质数
int primenum[maxn];//质数集合
int m=0;
void phi_init()
{
phi[1]=1;
memset(prime,true,sizeof prime);
prime[0]=prime[1]=false;
repp(i,2,maxn)
{
if (prime[i])
{
primenum[m++]=i;
phi[i]=i-1;
}
for (int j=0;j<m&&primenum[j]*i<maxn;j++)
{
prime[i*primenum[j]]=false;
if (i%primenum[j]==0)
{
phi[i*primenum[j]]=phi[i]*primenum[j];//第一条
break;//这里的break参考质数的线性筛解释
}
phi[i*primenum[j]]=phi[i]*phi[primenum[j]];//第二条
}
}
}
放一下质数线性筛做个对比
bool prime[maxn];
int m=1;
int primenum[maxn];
void prime_init()
{
memset(prime,true,sizeof prime);
prime[0]=prime[1]=false;
rep(i,2,maxn)
{
if (prime[i])primenum[m++]=i;
for (int j=1;j<m&&i*primenum[j]<=maxn;j++)
{
prime[i*primenum[j]]=false;
if (i%primenum[j]==0)break;
}
}
}
(六)例题
1.LightOJ - 1370
题意:给出n个数
x
i
x_i
xi,求
∑
i
=
1
n
a
i
\sum_{i=1}^na_i
∑i=1nai,
a
i
a_i
ai满足
φ
(
a
i
)
>
=
x
i
\varphi(a_i)>=x_i
φ(ai)>=xi
做法:预处理欧拉函数打表
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<queue>
#include<map>
#define ll long long
#define pb push_back
#define rep(x,a,b) for (int x=a;x<=b;x++)
#define repp(x,a,b) for (int x=a;x<b;x++)
#define W(x) printf("%d\n",x)
#define WW(x) printf("%lld\n",x)
#define pi 3.14159265358979323846
#define mem(a,x) memset(a,x,sizeof a)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
const int maxn=1e6+7;
const int INF=1e9;
const ll INFF=1e18;
int prime[maxn];
int primenum[maxn];
int phi[maxn];
void phi_init()
{
int m=0;
rep(i,1,maxn)prime[i]=1;
prime[0]=prime[1]=0;
phi[1]=1;
repp(i,2,maxn)
{
if (prime[i])
{
primenum[m]=i;
m++;
phi[i]=i-1;
}
for (int j=0;j<m&&i*primenum[j]<maxn;j++)
{
prime[i*primenum[j]]=0;
if (i%primenum[j]==0)
{
phi[i*primenum[j]]=phi[i]*primenum[j];
break;
}
phi[i*primenum[j]]=phi[i]*(primenum[j]-1);
}
}
}
int main()
{
phi_init();
int t,n,a;
scanf("%d",&t);
rep(K,1,t)
{
scanf("%d",&n);
ll sum=0;
rep(i,1,n)
{
scanf("%d",&a);
for (int j=a+1;j<maxn;j++)
{
if (phi[j]>=a)
{
sum+=j;
break;
}
}
}
printf("Case %d: %lld Xukha\n",K,sum);
}
return 0;
}