1. 程式人生 > 其它 >淺談線性篩能篩的函式

淺談線性篩能篩的函式

尤拉函式 \(φ(i)\)

尤拉函式是 \(1\sim n\) 的數中與 \(n\) 互質的個數,常寫成 phi

如何篩:

void init(){
  phi[1]=1;
  for(int i=2;i<=n;i++){
    if(!vis[i]){phi[i]=i-1;prime[++cnt]=i;}
    for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
      vis[i*prime[j]]=1;
      if(i%prime[j]==0){
		phi[i*prime[j]]=phi[i]*prime[j];
		break;
      }
      else phi[i*prime[j]]=phi[i]*phi[prime[j]];
    }
  }
}

對於 \(i\times prime\)​​ 中只出現過一次最小質因子 \(prime\)​​ 的情況(\(i\)​​ 與 \(prime\)​​ 互質),顯然對於 \(1\sim i\)​​ 中每一個與 \(i\)​​ 的數乘上 \(prime\)​​ ,都可以產生一個與 \(i\times prime\)​​ 互質的數;對於 \(i\times prime\)​​ 出現過兩次及以上個 \(prime\)​​ 的情況,就是要除掉 \(prime\)​​ 與 \(i\times prime\)​​ 這種情況(所以是 \(prime-1\)​​)。

莫比烏斯函式 \(\mu(i)\)

我太菜了,不知道這個函式的性質除了頹式子還有什麼用。

如何篩:

void get_mu(int n)
{
    mu[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!vis[i]){prim[++cnt]=i;mu[i]=-1;}
        for(int j=1;j<=cnt&&prim[j]*i<=n;j++)
        {
            vis[prim[j]*i]=1;
            if(i%prim[j]==0)break;
            else mu[i*prim[j]]=-mu[i];
        }
    }
 }

就這樣篩吧,就是根據百度百科上的性質來篩。

約數數和函式 \(\sigma(i)\)

字面意思,常寫成 sigma (其實符號就是小寫的 sigma

如何篩:(遠古的程式碼,有點沙比)

#include<bits/stdc++.h>
#define N 1000005
using namespace std;
int n,s[N],e[N],tot,p[N],v[N];
//tot:質數個數,p[i]:第i個質數,v[i]:i是否是質數
//s[i]:i的約數和,e[i]:不能被i的最小質因子整除的約數和
int main() {
    cin>>n;
    for(int i=2; i<=n; i++) {
        if(!v[i]) {//當i是質數時
            p[++tot]=i;//把i存進p
            s[tot]=1+i;//i的約數和等於1+自身
            e[tot]=1;//不能被i的最小質因子(即i)整除的約數和等於1
        }
        for(int j=1; j<=tot&&i*p[j]<=n; j++) {//詳解見下文
            v[i*p[j]]=1;
            if(i%p[j]) {//如果i和p[j]互質
                s[i*p[j]]=s[i]*(p[j]+1);
                //↑s[i*p[j]]=s[i]*s[j];這種寫法應該也可以
                e[i*p[j]]=s[i];
            } else {
                s[i*p[j]]=s[i]*p[j]+e[i];
                e[i*p[j]]=e[i];
                break;
            }
        }
    }
    int ans=0;
    for(int i=1; i<=n; i++) {//統計答案
        ans+=s[i];
    }
    cout<<ans;
    return 0;
}

約數個數和函式

字面意思,然而我也不知道符號表示是什麼。

如何篩:

void init(){
    f[1]=g[1]=1;
    for(int i=2;i<=M;++i){
        if(!vis[i]) pr[++pn]=i,f[i]=2,g[i]=1;
        for(int j=1;j<=pn&&i*pr[j]<=M;++j){
            vis[i*pr[j]]=1;
            if(i%pr[j]==0){
                g[i*pr[j]]=g[i]+1;
                f[i*pr[j]]=f[i]/(g[i]+1)*(g[i*pr[j]]+1);
                break;
            }
            else g[i*pr[j]]=1,f[i*pr[j]]=f[i]<<1;
        }
    }
}

我們對於一個數有唯一分解定理:\(p=p_1^{k_1}\times p_2^{k_2} ⋯ \times p_n^{k_n}\)

所以對於一個數的約數個數為:\(\prod (k_i+1)\)​ 表示每個分解出來的 \(p_i\) 選幾個,因為可以不選,所以 \(+1\)

我們定義 \(f(i)\)​ 為 \(i\) 的約數個數和,\(g(i)\)\(i\) 的最小質因子出現的次數(分解出來的對應的指數 \(k\))。

當然,可以證得 \(f(i)\) 是積性函式。

根據線性篩的流程,當 \(i\)​ 與 \(prime\)​ 互質時,\(g(i\times prime)=1\)​,因為新 \(i\times prime\)\(prime\) 的指數為 \(1\),所以約數個數要在 \(f(i)\) 的基礎上乘上 \(g(prime)+1=2=f(prime)\),也印證了 \(f(i)\) 是積性函式?\(f(i\times prime)=f(i)\times 2=f(i)\times f(prime)\)

反之,\(g(i\times prime)=g(i)+1\)\(f(i\times prime)=[g(i\times prime)+1]\times \frac{f(i)}{g(i)+1}\)​,意思是先把 \(f(i)\) 中的關於 \(prime\) 的貢獻項除掉,得出除掉 \(prime\) 以外的其他質因子的貢獻,再乘上新的 \(prime\) 的貢獻。