欧拉函数 | 欧拉筛
简述
欧拉函数ϕi(phii)表示<=i并且与i互质的数的个数。非完全积性函数。
欧拉筛是一种线性筛。时间复杂度O(UpperLimit)。可以用来线性求积性函数。
原理
欧拉筛
欧拉筛抓取当前的素数i与以前的素数Primes1∼Primescnt相乘,将它们筛除。欧拉筛保证每个合数都是由其最小的质因子筛除。
其核心代码为if(i % Primes[j] == 0) break;
,该句保证了欧拉筛的时间复杂度为线性。
证明:当imodPrimesj==0时,有两种可能:
- 当$ i 是一个素数。此时说明已经抓取到了i(Primes_j == i),筛去了i2$。显然地,对于素数$i$,$i2最小的质因子是i$。
- 当i是一个合数。此时说明Primesj是i最小的质因子。那么i∗Primesj的质因子即为Primesj和i的质因子。显然地,Primesj<i,那么Primesj到目前为止是i∗Primesj的最小质因子。但是$ Primes 数组为单调递增,之后筛的每一个iPrimes_{j’}的最小质因子已经不是Primes_{j’},而是前面的Primes_j(因为前面i \mod Primes_j == 0,那么Primes_j是i的最小质因子,也是iPrimes_j$的最小质因子),那么就不能保证每个合数都是由它的最小质因子筛除的了。所以
Break
。
另外,UpperLimit以内的每个合数都会被筛到。显然地,UpperLimit以内的每个数都拥有一个UpperLimit以内的质因子。
欧拉函数
ϕi的通用表达式:ϕi=i∗∏j=1cnti(1−pj1) ,使用容斥原理:
- 将i分解质因数,得到i=∏j=1cntpiei。p是i的质因子。那么<i的pj的任意倍数都不与i互质。这些数的个数为$ \frac{n}{p_1} + \frac{n}{p_2} + … \frac{n}{p_j}。用n减去这些数。当然会减到一些重叠起来的情况,也就是\frac{n}{p_1p_2}之类,把它们加回来就可以了。用容斥原理化一下这个式子,得到\phi_i = i * \prod_{j=1}^{cnt}(1-\frac{1}{p_i} )$。
ϕ有一些特别的性质。考虑ϕi:
-
显然地,当i是素数,那么ϕi=i−1。
-
当i可以被写成pk的形式,其中p是一个素数,那么ϕi=pk−pk−1。
? 证明:考虑pk,ϕpk 中的数必须满足一个要求,即不含有因子p。直接算不好算,考虑倒着算。pk内含有因子p的数为$ p,2p,3p,4p, \ldots,pp,(p+1)*p,\ldots,(p{k-1}-1)*p,p{k-1}*p,共p^{k-1}$个。
-
当i可以写成m∗n的形式,其中m,n互质,那么ϕi=ϕm∗ϕn。即欧拉函数的部分积性。
? 证明:m和n互质,说明m与n没有相同的质因子。那么他们的唯一分解式是完全不同的。即m=∏j=1cntmpjej,n=∏j=1cntnpjej。那么ϕm=m∗∏j=1cntm(1−pj1),ϕn=n∗∏j=1cntn(1−pj1)。因为唯一分解式完全不同,那么很显然ϕm∗n=ϕm∗ϕn。
根据ϕ的定义和ϕ的性质,考虑ϕi的递推求法:
实现
1 2 3 4 5 6 7 8 9 10
| #define rep(x,y,z) for(int x=y,I=z;x<=z;++x) inline void Euler_Sieve(){ rep(i,2,lim){ if(!isprime[i]) primes[++prime]=i,phi[i]=i-1; for(int j=1;i*primes[j]<=lim;j++){ phi[i*primes[j]]=phi[i]*(primes[j]-1),isprime[i*primes[j]]=true; if(i%primes[j]==0) { phi[i*primes[j]]=phi[i]*primes[j]; break; } } } }
|