線性篩詳解


線性篩,可以理解為用 \(O(n)\) 的時間復雜度處理 \(\leqslant n\) 定義域范圍內每個點對應的某個函數值。比如線性篩質數等。

而篩法的思想非常簡單,就是我們要求每一個數都被且僅被其最小的質因數篩掉,即只有在 \(pri[j] \leqslant min(prime(i))\) 時篩 。所以我們只需要在 \(i\) \(\%\) \(pri[j]\) == \(0\)\(break\) 掉就行了。(因為 \(pri[j]\) 是從小到大枚舉的,所以如果存在 \(i\) \(\%\) \(pri[j]\) == \(0\) 就說明 \(pri[j]\) 已經是 \(i\) 的最小質因子了)

那么現在我就介紹一下做題中常見的幾個使用線性篩的場合。

  1. 質數

線性篩質數是線性篩最基礎的內容,其思想就是最簡單的“用 \(i\) 的最小質因子篩掉 \(i\)”。不多解釋,直接貼代碼:

for(int i=2;i<=k;i++){
    if(tof[i] == false){
        tof[i] = true;
        prime[++tot] = i;
    }
    for(int j=1;j<=tot && i * prime[j] <= k;j++){
        tof[i * prime[j]] = true;
        if(i % prime[j] == 0) break;
    }
}
  1. 歐拉函數

歐拉函數計算公式:

\(\varphi (x) = x \cdot \prod (1 - \frac{1}{p_i})\)

接着我們沿用上面線性篩的思想考慮下這個問題。

\(k = pri[j]\)

如果 \(i\) \(\%\) \(k = 0\) ,則 \(k\)\(i\) 的最小質因子 。 此時 \(\varphi(i \cdot k) = \varphi(i) \cdot k\) 。然后直接 \(break\)

如果 \(i\) \(\%\) \(k \neq 0\) , 則 \(i\)\(k\) 互質 。此時 \(\varphi(i \cdot k) = \varphi(i) \cdot (k - 1)\)

以上兩個式子都可以將左右兩邊帶到原式中證明,不做贅述。

代碼:

for(int i=2;i<=n;i++){
    if(prime[i] == false){
        phi[i] = i - 1;
        p[++tot] = i;
    }
    for(int k=1;k<=tot && i * p[k] <= n;k++){
        int j = p[k];
        int now = i * j;
        prime[now] = true;
        if(i % j == 0){
            phi[now] = phi[i] * j;
            break;
        }
        phi[now] = phi[i] * (j - 1);
    }
}
  1. \(i^k\)\(k\) 給定)

可以看出,\(i^k\) 是完全積性函數。即若 \(i=a\cdot b\) ,則 \(i^k = (a \cdot b)^k = a^k \cdot b^k\)

而小於 \(n\) 的質數個數 \(\pi(i) \approx \frac{n}{\log n}\) 個。

所以直接快速冪求出所有質數的 \(p^k\) ,然后再用線性篩篩合數的 \(i^k\) 即可。

復雜度可視為線性。

代碼:

for(int i=2;i<=n;i++){
    if(prime[i] == false){
        kk[i] = ksm(i , pos);
        phi[i] = i - 1;
        p[++tot] = i;
    }
    for(int k=1;k<=tot && i * p[k] <= n;k++){
        int j = p[k];
        int now = i * j;
        prime[now] = true;
        kk[now] = kk[i] * kk[j] % mod;
        if(i % j == 0){
            phi[now] = phi[i] * j;
            break;
        }
        phi[now] = phi[i] * (j - 1);
    }
}
  1. \(\tau\)(約數個數)

約數個數計算公式:

\(x = \prod p_i^{ei}\)

\(\tau(x) = \prod (1+e_i)\)

觀察這個式子,我們發現它也有可線性篩的性質。

我們用 \(g_i\) 代表 \(i\) 這個數字的最小質因子的指數 $ + 1$ ,\(t_i\) 代表 \(\tau(i)\)

\(i\) 為質數,很顯然 \(t_i = g_i = 2\)

\(k = pri[j]\)

如果 \(i\) \(\%\) \(k = 0\) ,則 \(k\)\(i\) 的最小質因子 。 此時 \(t_{i \cdot k} = \frac{t_i \cdot (g_i + 1)}{g_i}\)\(g_{i \cdot k} = g_i + 1\) 。然后直接 \(break\)

如果 \(i\) \(\%\) \(k \neq 0\) , 則 \(i\)\(k\) 互質 ,且 \(k\) 小於 \(i\) 的最小質因子。此時 \(g_{i \cdot k} = 2\) , \(t_{i \cdot k} = 2t_i\)

和上面的線性篩歐拉函數大同小異。

for(int i=2;i<=MAXN;i++){
	if(tof[i] == false){
        g[i] = 2;
        t[i] = 2;
        prime[++tot] = i;
    }
    for(int j=1;j<=tot && prime[j] * i <= 1e6;j++){
        int k = prime[j];
        if(i % k != 0){
            g[i * k] = 2;
            t[i * k] = t[i] * 2;
            tof[i * k] = true;
        }
        else {
            t[i * k] = t[i] / g[i] * (g[i] + 1);
            g[i * k] = g[i] + 1;
            tof[i * k] = true;
            break;
        }
    }
}
  1. 線性求逆元

線性求逆元並不屬於線性篩,但由於它的復雜度為線性,所以我們在這里也簡述一下。

\(p = k \cdot i + r\)

\(k = \lfloor \frac{p}{i} \rfloor\)\(r =p \% i\)

那么可得:\(k \cdot i + r ≡ 0\) \((\bmod\) \(p)\)

同乘 \(i^{-1}\) , \(r^{-1}\) 可得:

\(k \cdot r^{-1} + i^{-1} ≡ 0\) \((\bmod\) \(p)\)

\(i^{-1} ≡ -k \cdot r^{-1}\) \((\bmod\) \(p)\)

\(i^{-1}≡ -\lfloor \frac{p}{i} \rfloor \cdot (p \% i)^{-1}\) \((\bmod\) \(p)\)

通過這個式子就可以線性求逆元了。

代碼:

inv[1] = 1;
for(int i = 2; i < p; ++ i)
    inv[i] = (p - p / i) * inv[p % i] % p;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM