1. 程式人生 > >莫比烏斯反演與積性函式部分(轉載)

莫比烏斯反演與積性函式部分(轉載)

莫比烏斯與積性函式

之前做過不少的數論題,關於莫比烏斯與積性函式的數論題挺多的。。。特地過來總結一下。。當作自己的一個回顧了-_-

先安利一下神犇tls的部落格和神犇PoPoQQQ的pdf !
膜拜tls…
跪popoqqq…
還有IOI金牌神犇任之州的集訓隊論文,都是好文啊!

需要先知道線性篩這個東西。。
orz…
線性篩的思想是每個合數都只會被它最小的質因數篩去,通過線性篩,我們可以O(n)得到1到n內一些數論函式的值,比如說尤拉函式、莫比烏斯函式、因子個數等等。。。

本文的除法均為整除,除非特別指出。
[expresion]為bool表示式,值為0或1,當且僅當expresion為真時為1,否則為0。


(i,j)表示gcd(i,j)。

莫比烏斯反演

莫比烏斯函式

首先定義莫比烏斯函式

u(i)=⎧⎩⎨1,(−1)k,0,if n = 1if n=p1∗p2∗...∗pk 其它u(i)={1,if n = 1(−1)k,if n=p1∗p2∗...∗pk 0,其它


根據上面的定義,n大於1時且n是平方因子數時莫比烏斯函式值為0,否則從n的唯一分解定理中根據素數的個數取奇偶即可。

莫比烏斯函式的性質:

1) ∑d|nu(d)=⎧⎩⎨1,0,if n = 1其它∑d|nu(d)={1,if n = 10,其它
有了上述這個式子,我們就可以直接簡單地以O(nlogn)篩出1到n內所有數的莫比烏斯函式值了~
至此我們已經有兩種辦法求1到n內所有數的尤拉函式值了。

//O(n)
bool vis[N];
int primes[N], miu[N];
int init(int n) {
    int tot = 0;
    miu[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!vis[i]) {
            primes[tot++] = i;
            miu[i] = -1;
        }
        for (int j = 0; j < tot; j++) {
            int k = i * primes[j];
            if (k > n)break;
            vis[k] = true;
            if (i % primes[j])  miu[k] = -miu[i];
            else break;
        }
    }
}
//O(nlogn)
void init(int n) {
    miu[1] = 1;
    int t = n >> 1;
    for (int i = 1; i <= t; i++) if (miu[i]) {
        for (int j = i << 1; j <= n; j += i) miu[j] -= miu[i];
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

2) ∑d|nu(d)d=φ(n)n∑d|nu(d)d=φ(n)n

莫比烏斯函式除了可以用在莫比烏斯反演中之外,還可以用來進行容斥。
舉一個常見的例子,求取1到n這個區間內有多少個數與x互質,一般的做法是直接進行容斥,但是我們可以發現容斥的係數剛好是莫比烏斯函式,即ans = ∑d|xu(d)∗nd∑d|xu(d)∗nd,其實這兩者從本質考慮是完全等價的。

莫比烏斯反演

莫比烏斯反演是一個這樣的式子:
定義F(n)=∑d|nf(n)F(n)=∑d|nf(n),那麼可以得到f(n)=∑d|nu(nd)F(d)f(n)=∑d|nu(nd)F(d)
莫比烏斯反演還有一種更常見的形式:F(n)=∑n|df(d)F(n)=∑n|df(d), 那麼有f(n)=∑n|du(dn)F(d)f(n)=∑n|du(dn)F(d)。
一般應用的都是上述的第二種形式,證明可以通過歸納得出,也可以直接通過式子變換得出,還可以由狄利克雷卷積證明。
f(n)=∑d|nu(nd)F(d)=∑d|nu(nd)∑x|df(x)=∑d|nf(d)∑x|ndu(x)=f(n)f(n)=∑d|nu(nd)F(d)=∑d|nu(nd)∑x|df(x)=∑d|nf(d)∑x|ndu(x)=f(n)
上述的證明中給出了一種常見的和式變換技巧:交換求和順序。通過交換求和順序,我們往往可以將某些和式化簡或者更容易求出該和式,後面公式的化簡將多次用到。

莫比烏斯反演還有一個推廣式,如下:
這裡寫圖片描述

積性函式

積性函式定義

設f(x)f(x)為一個數論函式,如果對於任意正整數a、b滿足(a,b)=1(a,b)=1,有f(ab)=f(a)∗f(b)f(ab)=f(a)∗f(b)的話,我們稱f(n)f(n)為積性函式;如果對於任意正整數啊a、b有f(ab)=f(a)∗f(b)f(ab)=f(a)∗f(b)的話,我們稱f(n)f(n)為完全積性函式。
常見的積性函式有:
因子個數函式d(n)d(n),因子和函式σ(n)σ(n),二元函式gcd(a,b)gcd(a,b),尤拉函式φ(n)φ(n),莫比烏斯函式u(n)u(n)。
完全積性函式有:
元函式e(n)=[n==1]e(n)=[n==1],恆等函式I(n)=1I(n)=1,單位函式id(n)=nid(n)=n。

積性函式應用

我們來看看積性函式的應用:
如果f(x)f(x)為積性函式且n=∑ti=1peiin=∑i=1tpiei,那麼可以得到f(n)=∏ti=1f(peii)f(n)=∏i=1tf(piei),如果f(x)為完全積性函式,那麼我們還可以進一步得到f(n)=∏ti=1f(pi)eif(n)=∏i=1tf(pi)ei。
舉個簡單的例子:因子個數d(n)=∏ti=1d(peii)=∏ti=1(ei+1)d(n)=∏i=1td(piei)=∏i=1t(ei+1),因子和函式σ(n)=∏ti=1σ(peii)=∏ti=1piei+1−1pi−1σ(n)=∏i=1tσ(piei)=∏i=1tpiei+1−1pi−1。
積性函式還可以用來進行線性篩從而得到很多數論函式的值~
比如下面的尤拉函式:
可以知道當i%p==0i%p==0時,φ(i∗p)=φ(i)∗pφ(i∗p)=φ(i)∗p,而當i%p!=0i%p!=0時,有

φ(i∗p)=φ(i)∗φ(p)=φ(i)∗(p−1)φ(i∗p)=φ(i)∗φ(p)=φ(i)∗(p−1)

const int N = 1e6 + 5;
bool vis[N];
int phi[N], p[N], cnt = 0;
void seive() {
    cnt = 0;
    phi[1] = 1;
    for (int i = 2; i < N; i++) {
        if (!vis[i]) p[cnt++] = i, phi[i] = i - 1;
        for (int j = 0; j < cnt; j++) {
            int s = i * p[j];
            if (s > N) break;
            vis[s] = 1;
            if (i % p[j] == 0) {
                phi[s] = p[j] * phi[i];
                break;
            }
            phi[s] = (p[j] - 1) * phi[i];
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

積性函式字首和

積性函式的和也是積性函式,積性函式字首和是一個常見的問題,常常需要低於線性時間內解決。

狄利克雷卷積

狄利克雷卷積是解決積性函式字首和問題的一個重要工具。

定義

對兩個算術函式f, g,定義其Dirichlet卷積為新函式f * g,滿足(f∗g)(n)=∑d|nf(d)g(nd)(f∗g)(n)=∑d|nf(d)g(nd)。
狄利克雷卷積滿足以下定律:
這裡寫圖片描述
若f,g均為積性函式,則f*g也是積性函式。
我們可以O(nlogn)預處理兩個函式的Dirichlet卷積。

LL f[N], g[N], h[N];
void calc(int n) {
    for (int i = 1; i * i <= n; i++) {
        h[i * i] += f[i] * g[i];
        for (int j = i + 1; i * j <= n; j++) h[i * j] += f[i] * g[j] + f[j] * g[i];
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

舉例

很多數論函式都可以用狄利克雷卷積來表示:
①約數個數函式d(n)=(I∗I)(n)d(n)=(I∗I)(n);
②約數和函式d(n)=(I∗id)(n)d(n)=(I∗id)(n);
③∑d|nu(d)=[n==1]∑d|nu(d)=[n==1],得到I∗u=eI∗u=e。
④∑d|nφ(d)=n∑d|nφ(d)=n,得到I∗φ=idI∗φ=id。

現在我們可以通過狄利克雷卷積來證明莫比烏斯反演了:
如果F(n)=∑d|nf(n)F(n)=∑d|nf(n),那麼F = I*f,那麼可以知道F*u = I*f*u=f*(I*u)=f*e=f,所以f(n)=∑d|nu(nd)F(d)f(n)=∑d|nu(nd)F(d)。

應用

設f(n)為一個數論函式,需要計算S(n)=∑ni=1f(i)S(n)=∑i=1nf(i),通常n>=1e9。
要解決上述問題,我們可以構造一個S(n)S(n)關於S(ni)S(ni)的遞推式。
找到一個合適的數論函式g(n),

∑i=1n∑d|if(d)g(id)=∑i=1ng(i)∑j=1nif(j)=∑i=1ng(i)S(ni)∑i=1n∑d|if(d)g(id)=∑i=1ng(i)∑j=1nif(j)=∑i=1ng(i)S(ni)


這樣,可以知道g(1)S(n)=∑ni=1(f∗g)(i)−∑ni=2g(i)∗S(ni)g(1)S(n)=∑i=1n(f∗g)(i)−∑i=2ng(i)∗S(ni)。
構造的卷積函式必須容易求得字首和,這樣我們可以記憶化地計算S(n),因為nini是分段的,可以計算出複雜度為O(n34)O(n34),只要我們預處理S函式前2323的值,複雜度就可以達到O(n23)O(n23)
上述的辦法就是傳說中的杜教篩了~
如果找不到適合的函式g(n),那麼可以採用一種複雜度為O(n34logn)O(n34logn)的辦法來實現求和,詳見任之州的論文。

下面給出

莫比烏斯與積性函式

之前做過不少的數論題,關於莫比烏斯與積性函式的數論題挺多的。。。特地過來總結一下。。當作自己的一個回顧了-_-

先安利一下神犇tls的部落格和神犇PoPoQQQ的pdf !
膜拜tls…
跪popoqqq…
還有IOI金牌神犇任之州的集訓隊論文,都是好文啊!

需要先知道線性篩這個東西。。
orz…
線性篩的思想是每個合數都只會被它最小的質因數篩去,通過線性篩,我們可以O(n)得到1到n內一些數論函式的值,比如說尤拉函式、莫比烏斯函式、因子個數等等。。。

本文的除法均為整除,除非特別指出。
[expresion]為bool表示式,值為0或1,當且僅當expresion為真時為1,否則為0。
(i,j)表示gcd(i,j)。

莫比烏斯反演

莫比烏斯函式

首先定義莫比烏斯函式

u(i)=⎧⎩⎨1,(−1)k,0,if n = 1if n=p1∗p2∗...∗pk 其它u(i)={1,if n = 1(−1)k,if n=p1∗p2∗...∗pk 0,其它


根據上面的定義,n大於1時且n是平方因子數時莫比烏斯函式值為0,否則從n的唯一分解定理中根據素數的個數取奇偶即可。

莫比烏斯函式的性質:

1) ∑d|nu(d)=⎧⎩⎨1,0,if n = 1其它∑d|nu(d)={1,if n = 10,其它
有了上述這個式子,我們就可以直接簡單地以O(nlogn)篩出1到n內所有數的莫比烏斯函式值了~
至此我們已經有兩種辦法求1到n內所有數的尤拉函式值了。

//O(n)
bool vis[N];
int primes[N], miu[N];
int init(int n) {
    int tot = 0;
    miu[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!vis[i]) {
            primes[tot++] = i;
            miu[i] = -1;
        }
        for (int j = 0; j < tot; j++) {
            int k = i * primes[j];
            if (k > n)break;
            vis[k] = true;
            if (i % primes[j])  miu[k] = -miu[i];
            else break;
        }
    }
}
//O(nlogn)
void init(int n) {
    miu[1] = 1;
    int t = n >> 1;
    for (int i = 1; i <= t; i++) if (miu[i]) {
        for (int j = i << 1; j <= n; j += i) miu[j] -= miu[i];
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

2) ∑d|nu(d)d=φ(n)n∑d|nu(d)d=φ(n)n

莫比烏斯函式除了可以用在莫比烏斯反演中之外,還可以用來進行容斥。
舉一個常見的例子,求取1到n這個區間內有多少個數與x互質,一般的做法是直接進行容斥,但是我們可以發現容斥的係數剛好是莫比烏斯函式,即ans = ∑d|xu(d)∗nd∑d|xu(d)∗nd,其實這兩者從本質考慮是完全等價的。

莫比烏斯反演

莫比烏斯反演是一個這樣的式子:
定義F(n)=∑d|nf(n)F(n)=∑d|nf(n),那麼可以得到f(n)=∑d|nu(nd)F(d)f(n)=∑d|nu(nd)F(d)
莫比烏斯反演還有一種更常見的形式:F(n)=∑n|df(d)F(n)=∑n|df(d), 那麼有f(n)=∑n|du(dn)F(d)f(n)=∑n|du(dn)F(d)。
一般應用的都是上述的第二種形式,證明可以通過歸納得出,也可以直接通過式子變換得出,還可以由狄利克雷卷積證明。
f(n)=∑d|nu(nd)F(d)=∑d|nu(nd)∑x|df(x)=∑d|nf(d)∑x|ndu(x)=f(n)f(n)=∑d|nu(nd)F(d)=∑d|nu(nd)∑x|df(x)=∑d|nf(d)∑x|ndu(x)=f(n)
上述的證明中給出了一種常見的和式變換技巧:交換求和順序。通過交換求和順序,我們往往可以將某些和式化簡或者更容易求出該和式,後面公式的化簡將多次用到。

莫比烏斯反演還有一個推廣式,如下:
這裡寫圖片描述

積性函式

積性函式定義

設f(x)f(x)為一個數論函式,如果對於任意正整數a、b滿足(a,b)=1(a,b)=1,有f(ab)=f(a)∗f(b)f(ab)=f(a)∗f(b)的話,我們稱f(n)f(n)為積性函式;如果對於任意正整數啊a、b有f(ab)=f(a)∗f(b)f(ab)=f(a)∗f(b)的話,我們稱f(n)f(n)為完全積性函式。
常見的積性函式有:
因子個數函式d(n)d(n),因子和函式σ(n)σ(n),二元函式gcd(a,b)gcd(a,b),尤拉函式φ(n)φ(n),莫比烏斯函式u(n)u(n)。
完全積性函式有:
元函式e(n)=[n==1]e(n)=[n==1],恆等函式I(n)=1I(n)=1,單位函式id(n)=nid(n)=n。

積性函式應用

我們來看看積性函式的應用:
如果f(x)f(x)為積性函式且n=∑ti=1peiin=∑i=1tpiei,那麼可以得到f(n)=∏ti=1f(peii)f(n)=∏i=1tf(piei),如果f(x)為完全積性函式,那麼我們還可以進一步得到f(n)=∏ti=1f(pi)eif(n)=∏i=1tf(pi)ei。
舉個簡單的例子:因子個數d(n)=∏ti=1d(peii)=∏ti=1(ei+1)d(n)=∏i=1td(piei)=∏i=1t(ei+1),因子和函式σ(n)=∏ti=1σ(peii)=∏ti=1piei+1−1pi−1σ(n)=∏i=1tσ(piei)=∏i=1tpiei+1−1pi−1。
積性函式還可以用來進行線性篩從而得到很多數論函式的值~
比如下面的尤拉函式:
可以知道當i%p==0i%p==0時,φ(i∗p)=φ(i)∗pφ(i∗p)=φ(i)∗p,而當i%p!=0i%p!=0時,有

φ(i∗p)=φ(i)∗φ(p)=φ(i)∗(p−1)φ(i∗p)=φ(i)∗φ(p)=φ(i)∗(p−1)

const int N = 1e6 + 5;
bool vis[N];
int phi[N], p[N], cnt = 0;
void seive() {
    cnt = 0;
    phi[1] = 1;
    for (int i = 2; i < N; i++) {
        if (!vis[i]) p[cnt++] = i, phi[i] = i - 1;
        for (int j = 0; j < cnt; j++) {
            int s = i * p[j];
            if (s > N) break;
            vis[s] = 1;
            if (i % p[j] == 0) {
                phi[s] = p[j] * phi[i];
                break;
            }
            phi[s] = (p[j] - 1) * phi[i];
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

積性函式字首和

積性函式的和也是積性函式,積性函式字首和是一個常見的問題,常常需要低於線性時間內解決。

狄利克雷卷積

狄利克雷卷積是解決積性函式字首和問題的一個重要工具。

定義

對兩個算術函式f, g,定義其Dirichlet卷積為新函式f * g,滿足(f∗g)(n)=∑d|nf(d)g(nd)(f∗g)(n)=∑d|nf(d)g(nd)。
狄利克雷卷積滿足以下定律:
這裡寫圖片描述
若f,g均為積性函式,則f*g也是積性函式。
我們可以O(nlogn)預處理兩個函式的Dirichlet卷積。

LL f[N], g[N], h[N];
void calc(int n) {
    for (int i = 1; i * i <= n; i++) {
        h[i * i] += f[i] * g[i];
        for (int j = i + 1; i * j <= n; j++) h[i * j] += f[i] * g[j] + f[j] * g[i];
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

舉例

很多數論函式都可以用狄利克雷卷積來表示:
①約數個數函式d(n)=(I∗I)(n)d(n)=(I∗I)(n);
②約數和函式d(n)=(I∗id)(n)d(n)=(I∗id)(n);
③∑d|nu(d)=[n==1]∑d|nu(d)=[n==1],得到I∗u=eI∗u=e。
④∑d|nφ(d)=n∑d|nφ(d)=n,得到I∗φ=idI∗φ=id。

現在我們可以通過狄利克雷卷積來證明莫比烏斯反演了:
如果F(n)=∑d|nf(n)F(n)=∑d|nf(n),那麼F = I*f,那麼可以知道F*u = I*f*u=f*(I*u)=f*e=f,所以f(n)=∑d|nu(nd)F(d)f(n)=∑d|nu(nd)F(d)。

應用

設f(n)為一個數論函式,需要計算S(n)=∑ni=1f(i)S(n)=∑i=1nf(i),通常n>=1e9。
要解決上述問題,我們可以構造一個S(n)S(n)關於S(ni)S(ni)的遞推式。
找到一個合適的數論函式g(n),

∑i=1n∑d|if(d)g(id)=∑i=1ng(i)∑j=1nif(j)=∑i=1ng(i)S(ni)∑i=1n∑d|if(d)g(id)=∑i=1ng(i)∑j=1nif(j)=∑i=1ng(i)S(ni)


這樣,可以知道g(1)S(n)=∑ni=1(f∗g)(i)−∑ni=2g(i)∗S(ni)g(1)S(n)=∑i=1n(f∗g)(i)−∑i=2ng(i)∗S(ni)。
構造的卷積函式必須容易求得字首和,這樣我們可以記憶化地計算S(n),因為nini是分段的,可以計算出複雜度為O(n34)O(n34),只要我們預處理S函式前2323的值,複雜度就可以達到O(n23)O(n23)
上述的辦法就是傳說中的杜教篩了~
如果找不到適合的函式g(n),那麼可以採用一種複雜度為O(n34logn)O(n34logn)的辦法來實現求和,詳見任之州的論文。

下面給出求積性函式字首和時常用到的一些公式和結論:
①∑d|nu(d)=[ns==1]∑d|nu(d)=[n==1]。
②∑d|nφ(d)=n∑d|nφ(d)=n。
③∑ni=1i∗[(i,n)==1]=n∗φ(n)+[n==1]2∑i=1ni∗[(i,n)==1]=n∗φ(n)+[n==1]2。
④d(n2)=∑d|n2w(d)=∑d|n∑i|du2(i)d(n2)=∑d|n2w(d)=∑d|n∑i|du2(i),w(d)表示d的不同質因子的個數。
⑤d(n∗m)=∑i|n∑j|m[(i,j)==1]。d(n∗m)=∑i|n∑j|m[(i,j)==1]。

∑i=1n[(i,n)==1]∗(i−1,n)=∑d|n∑i=1n[(i,n)==1]∗[d|(i−1)]=∑d|nφ(d)∗φ(n)φ(d)=d(n)∗φ(n)。∑i=1n[(i,n)==1]∗(i−1,n)=∑d|n∑i=1n[(i,n)==1]∗[d|(i−1)]=∑d|nφ(d)∗φ(n)φ(d)=d(n)∗φ(n)。


⑦d|i∗j等價於d(i,d)|jd|i∗j等價於d(i,d)|j
上面的幾個東西有些是很顯然的,但是還是寫出來放在一起好了,至於第六個本人能力過弱不知如何證明。。。

求積性函式字首和時常用到的一些公式和結論:
①∑d|nu(d)=[n==1]∑d|nu(d)=[n==1]。
②∑d|nφ(d)=n∑d|nφ(d)=n。
③∑ni=1i∗[(i,n)==1]=n∗φ(n)+[n==1]2∑i=1ni∗[(i,n)==1]=n∗φ(n)+[n==1]2。
④d(n2)=∑d|n2w(d)=∑d|n∑i|du2(i)d(n2)=∑d|n2w(d)=∑d|n∑i|du2(i),w(d)表示d的不同質因子的個數。
⑤d(n∗m)=∑i|n∑j|m[(i,j)==1]。d(n∗m)=∑i|n∑j|m[(i,j)==1]。

∑i=1n[(i,n)==1]∗(i−1,n)=∑d|n∑i=1n[(i,n)==1]∗[d|(i−1)]=∑d|nφ(d)∗φ(n)φ(d)=d(n)∗φ(n)。∑i=1n[(i,n)==1]∗(i−1,n)=∑d|n∑i=1n[(i,n)==1]∗[d|(i−1)]=∑d|nφ(d)∗φ(n)φ(d)=d(n)∗φ(n)。


⑦d|i∗j等價於d(i,d)|jd|i∗j等價於d(i,d)|j
上面的幾個東西有些是很顯然的,但是還是寫出來放在一起好了,至於第六個本人能力過弱不知如何證明。。。