banner
genkaim

genkaim

Darkmode,yes \q(≧▽≦q) 主题来自@birdgg

素数筛法|欧拉函数|欧拉筛法 埃氏筛法 详解

cover

定义#

欧拉函数是由nn指向 小于等于nn且与nn互质的正整数个数 的函数,用phi(n)phi(n)表示。

example

phi(2) = 1,(1)
phi(3) = 2,(1,2)
phi(4) = 2,(1,3)
phi(5) = 4,(1,2,3,4)
phi(6) = 2,(1,5)

公式#

结论#

假设 n 的质因数分解为p1a×p2b×...×pmkp_1^a \times p_2^b \times ... \times p_m^kpip_i是质因数),则欧拉函数可以用公式求得:
phi(n)=n×(11p1)×(11p2)×...×(11pm)phi(n) = n \times (1- \cfrac{1}{p_1} ) \times (1- \cfrac{1}{p_2} ) \times ... \times (1-\cfrac{1}{p_m})

推导#

首先一个数xxnn互质,说明没有公共的质因子,即xx不能有p1p_1p2p_2、...pmp_m等质因子。
那么1...n1...n中有p1p_1质因子的个数为npi\cfrac{n}{p_i}
同样,对质因子pip_i1...n1...n中有npi\cfrac{n}{p_i}个 数带pip_i质因子。
显然,没有pip_i的质因子的数量,就是要减去npi\cfrac{n}{p_i},即nsum(npi)n-sum(\cfrac{n}{p_i})

加上重复减去的数,根据容斥原理就得到了:

·phi(n)=nsum(npi)+sum(npi×pj)...+(1)m×np1×p2×...×pm=n(11p1)×(11p2)...(11pm)phi(n) = n - sum( \cfrac{n}{p_i} ) + sum( \cfrac{n}{p_i \times p_j} ) - ... + (-1)^m \times \cfrac{n}{p_1 \times p_2} \times ...\times p_m =n(1- \cfrac{1}{p_1}) \times (1-\cfrac{1}{p_2})...(1-\cfrac{1}{p_m})

朴素算法#

1#

根据定义,直接枚举1...n1...n里与nn的最大公约数是 1 的个数。

  for(int i=1; i<=n; i++)
    ans += gcd(n, i)==1;

2#

根据公式

phi(n)=n×(11p1)×(11p2)×...×(11pm)phi(n) = n \times (1- \cfrac{1}{p_1} ) \times (1- \cfrac{1}{p_2} ) \times ... \times (1-\cfrac{1}{p_m})

循环求质因子,在过程中计算 ans=ans*(1-1/pi) , 即 ans-= ans/pi

  ans = n;
  for(int i=2; i*i<=n; i++) {
    if(n%i==0) {
      ans -= ans/i;
      while(n%i==0) n/=i;
    }
  }
  if(n>1) ans -= ans/n;

筛法解法#

埃氏筛法#

根据欧拉函数的定义,phi(x)=x×(11pi)phi(x)=x \times (1- \cfrac{1}{p_i})

埃氏筛法的原理是用素数pip_i 筛所有的倍数j×pij \times p_i,说明此时j×pij \times p_i有一个质因数pip_i,因此可以用上面的公式进行递推。

  • 首先 phi [x] = x
  • 对每个素数pip_i的倍数 j , 有 phi [j] *= (1-1/pi),也即 phi [j] -= phi [j]/pi
    • 如果对于某个 i,其 phi [i] != i,说明之前筛过,是合数
void shai(int mx) {
  for(int i=1; i<=mx; i++)
    phi[i] = i;
  for(int i=2; i<=mx; i++) {
    if(phi[i] != i) continue;
    for(int j=i; j<=mx; j+=i)
      phi[j] -= phi[j]/i;
  }
}

欧拉筛法#

对于某个质数pip_i,分两种情况分析:

  1. 如果是 x 的质因子,则对x×pix \times p_i 来说,pi 已经在欧拉函数里计算了(11pi)(1-\cfrac{1}{p_i}),因此有:phi(x×pi)=phi(x)×piphi(x \times p_i) = phi(x) \times p_i
  2. 如果不是 x 的质因子,则对x×pix \times pi来说又多了一个质因子,有:phi(x×pi)=phi(x)×pi×(11pi)=phi(x)×(pi1)phi(x \times p_i) = phi(x) \times p_i \times (1- \cfrac{1}{p_i}) = phi(x) \times (p_i - 1)

结合欧拉筛法,就可以求 phi [x] 的代码。

void shai(int mx) {
  phi[1] = 1;
  for(int i=2; i<=mx; i++) {
    if(!notPrime[i]) {
      p[++last] = i;
      phi[i] = i-1;
    }
    for(int j=1; j<=last; j++) {
      int t = i * p[j];
      if(t>=mx) break;
      notPrime[t] = true;
      if(i % p[j]==0) {
        phi[t] = phi[i] * p[j];
        break;
      } else
       phi[t]= phi[i] * (p[j]-1);
    }
  }
}
加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。