尤拉函式、整除分塊和擴充套件歐幾里得

Yaosicheng124發表於2024-05-16

尤拉函式

尤拉函式(寫作 \(\varphi(x)\)),表示 \(i\in[1,x] 且 \gcd(i,x)=1\)\(i\) 的數量。

乍一看好像很難求,但我們先考慮最簡單的情況,即 \(x\in \mathbb{P}\)\(\mathbb{P}\) 表示質數集) 的情況。

首先很容易看出 \(\varphi(x)=x-1\),因為 \(x\in \mathbb{P}\),所以 \(\forall i \in [1,x-1]\) 都有 \(\gcd (i,x)=1\)

接著,我們可以想到 \(\varphi (x^2)=x^2-x\),因為總共 \(x^2\) 個數,\(x\) 的倍數都不合法,總共 \(\frac{x^2}{x}=x\)\(x\) 的倍數。

繼續,\(\varphi (x^3)=x^3-x^2\),因為總共 \(x^3\) 個數,\(x\) 的倍數都不合法,總共 \(\frac{x^3}{x}=x^2\)\(x\) 的倍數。

$\vdots $

最終,我們可以得到 \(\forall k \ge 1,\varphi (x^k)=x^k-x^{k-1}=(x-1)x^{k-1}\)

接著,我們來考慮這個問題:當 \(\gcd(a,b)=1\) 時,\(\varphi(a\cdot b)=\varphi(a)\cdot\varphi(b)\)。(即證尤拉函式是積性函式)

我們來感性理解一下,對於所有 \(x\le a且\gcd(x,a)=1\) 的數 \(x\)\(y \le b 且 \gcd(y,b)=1\)\(y\),那麼 \(\gcd(x\cdot y,a\cdot b)=1\),因為 \(x\) 的質因子 \(a\) 都沒有,\(y\) 的質因子 \(b\) 也都沒有,所以相乘後仍然沒有。即每個 \(x\cdot y\) 為一個合法的數,所以 \(\varphi(a\cdot b)=\varphi (a)\cdot \varphi(b)\)

接下來我們就可以求解 \(\varphi(x)\) 了。

方法1

這種方法可以 \(O(\sqrt x)\) 求出一個單獨的 \(\varphi (x)\)

首先我們可以把 \(x\) 拆成這樣:\(x=p_1^{e_1}\cdot p_2^{e_2}\cdot p_3^{e_3}\cdot \cdots\)

接著,透過 \(\varphi(a\cdot b)=\varphi(a)\cdot \varphi(b)\),我們可以將式子變成 \(\varphi(x)=\varphi (p_1^{e_1})\cdot \varphi(p_2^{e_2})\cdot \varphi(p_3^{e_3})\cdot \cdots\)

最終我們就可以得到 \(\varphi(x)=(p_1-1)\cdot p_1^{e_1-1}\cdot (p_2-1)\cdot p_2^{e_2-1}\cdot (p_3-1)\cdot p_3^{e_3-1}\cdot \cdots\)。而這段直接用分解質因數求解即可。

程式碼

int phi(int x) {
  int res = 1;
  for(int i = 2; i * i <= x; ++i) {
    if(x % i == 0) {
      x /= i, res *= i - 1;
      for(; x % i == 0; x /= i, res *= i) {
      }
    }
  }
  return res * (x > 1 ? x - 1 : 1);
}

phi(x);

方法2

這種方法可以 \(O(N)\) 求出 \(\forall x\in [1,N]\)\(\varphi(x)\),並且尤拉篩及其相似。

首先我們可以直接在篩出質數時求解,並且可以找到一個數的最小質因子,而這種方法就是透過最小質因子求解的。

當列舉到質數 \(p\),倍數為 \(i\)

  • 如果 \(\gcd(p,i)=1\),那麼 \(\varphi (p\cdot i)=\varphi(i)\cdot(p-1)\)
  • 否則,\(\varphi(p \cdot i)=\varphi(i)\cdot p\),因為相當於讓 \(p\) 的指數加一,所以答案乘以 \(p\)

程式碼

int phi[MAXN];
vector<int> prime;

void C(int x) {
  phi[1] = 1;
  for(int i = 2; i <= x; ++i) {
    if(!phi[i]) {
      phi[i] = i - 1;
      prime.push_back(i);
    }
    for(int p : prime) {
      if(i * p > x) {
        break;
      }
      if(i % p == 0) {
        phi[i * p] = phi[i] * p;
        break;
      }
      phi[i * p] = phi[i] * phi[p];
    }
  }
}

C(n);

整除分塊

整除分塊,就是 \(O(\sqrt k)\) 求解類似於 \(\sum \limits_{i=1}^{N} \lfloor\frac{k}{i}\rfloor\) 的式子。

整除分塊的主要思想就是列舉 \(\lfloor\frac{k}{i}\rfloor\) 的值,因為我們可以證明值的數量是 \(O(\sqrt k)\) 級別的:

  • \(i \le \sqrt k\) 時,\(\lfloor \frac{k}{i} \rfloor\) 的數量很明顯 \(\le \sqrt k\)
  • \(i > \sqrt k\) 時,\(\lfloor \frac{k}{i} \rfloor \le \sqrt k\),即 \(\lfloor \frac{k}{i} \rfloor\) 的數量 \(\le \sqrt k\)

所以總共是 \(O(\sqrt k)\) 級別的。

假設我們知道一個值出現的最早位置為 \(l\),那麼怎麼求最後一個位置 \(r\) 呢?

\[\begin{array}{l} \lfloor \frac{k}{l}\rfloor=\lfloor \frac{k}{r}\rfloor\\ \lfloor \frac{k}{l}\rfloor \cdot r \le k\\ r \le \frac{k}{\lfloor \frac{k}{l}\rfloor},即r=\lfloor\frac{k}{\lfloor \frac{k}{l}\rfloor}\rfloor \end{array} \]

程式碼

int ans;

for(int l = 1, r = 1; l <= min(k, n); l = r + 1) {
   r = min(n, k / (k / l));
   ans += (k / l) * (r - l + 1);
}

擴充套件歐幾里得

擴充套件歐幾里得 \(O(\sqrt{\min(a,b)})\) 求出 \(ax+by=c\)\(\gcd(a,b) | c\))的一組整數解。

直接開推(這裡只考慮 \(c=\gcd(a,b)\) 的情況,其餘情況將答案 \(\times k\) 即可):

\[\begin{array}{l} ax+by=\gcd(a,b)\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \Downarrow\\ b \cdot x' + (a-\lfloor\frac{a}{b}\rfloor \cdot b)\cdot y'=\gcd(b,a \bmod b)\\ b\cdot x'+a\cdot y'-\lfloor \frac{a}{b} \rfloor \cdot by'=\gcd(b,a \bmod b)\\ a\cdot y'+b\cdot (x'-\lfloor \frac{a}{b} \rfloor\cdot y')=\gcd(b,a \bmod b)\\ \therefore ax+by=\gcd(a,b)=a\cdot y'+b\cdot (x'-\lfloor \frac{a}{b} \rfloor\cdot y')\\ \therefore 當\begin{cases}x=y'\\y=(x'-\lfloor \frac{a}{b} \rfloor \cdot y')\end{cases} 時是一組合法的解。 \end{array} \]

只需按照上述方法不斷操作直到 \(b=0\) 時即可。(當 \(b=0\) 時的一組解解為 \(\begin{cases}x=1\\y=0\end{cases}\)

程式碼

using pii = pair<int, int>;

pii exgcd(int a, int b) {
  if(!b) {
    return {1, 0};
  }
  auto [x, y] = exgcd(b, a % b);
  return {y, x - a / b * y};
}

相關文章