banner
genkaim

genkaim

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

素数篩法|オイラー関数|オイラー篩法 エラトステネスの篩法 詳解

封面

定義#

歐拉函數是由nn指向 小於等於nn且與nn互質的正整數個數 的函數,用phi(n)phi(n)表示。

範例

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);
    }
  }
}
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。