1. 程式人生 > 實用技巧 >積性函式和篩法

積性函式和篩法

定義

若函式 \(f(n)\) 滿足 \(f(1)=1\)\(\forall x,y \in {\Bbb{N}}_{+},{\rm{gcd}}(x,y)=1\) 都有 \(f(xy)=f(x)f(y)\) ,則 \(f\) 為積性函式。

若函式 \(f(n)\) 滿足 \(f(1)=1\)\(\forall x,y \in {\Bbb{N}}_{+}\) 都有 \(f(xy)=f(x)f(y)\) ,則 \(f\) 為完全積性函式。

性質

比較重要的有:若 \(f,g\) 為積性函式,則滿足

\[h(n)=\sum_{d|n}f(d)g(\frac{n}{d}) \]

的函式 \(h\)

也為積性函式。

函式 \(h\) 稱作 \(f,g\) 的Dirichlet卷積,記作 \(f*g\)

例子

單位函式

\[\epsilon(n)=[n=1] \]

有:

\[\epsilon=\mu*{\rm{I}} \iff \epsilon(n)=\sum_{d|n}\mu(d) \]

這個式子尤其常用。

任何函式卷 \(\epsilon\) 都為其本身。

恆等函式

\[{\rm{id}}_k(n)=n^k \]

一般用 \({\rm{id}}\) 表示 \({\rm{id}}_1\)

常數函式

\[{\rm{I}}(n)=1 \]

在杜教篩中有用到。

除數函式

\[\sigma_k(n)=\sum_{d|n}d^k \]

一般 \(\sigma_0\) 記作 \({\rm{d}}\)\(\sigma_1\) 記作 \(\sigma\)

對於 \(\sigma\) ,有:

\[\sigma={\rm{id}}*{\rm{I}} \iff \sigma(n)=\sum_{d|n}d \]

線性篩 \({\rm{d}}\)

\(n=\prod_{i=1}^mp_i^{c_i}\) ,則根據乘法原理有:

\[{\rm{d}}(n)=\prod_{i=1}^m(c_i+1) \]

  • 對於質數 \(p\) ,有 \({\rm{d}}(p)=2\)
  • 對於 \(a,b\) 滿足 \(a\bot b\) ,有 \({\rm{d}}(ab)={\rm{d}}(a){\rm{d}}(b)\)
  • 對於質數 \(p\) 與合數 \(a\) 滿足 \(p|a\) ,設 \(c\)\(p\)\(pa\) 中的次數,有 \({\rm{d}}(pa)={\rm{d}}(a)\frac{c+1}{c}\)

於是就可以線性篩了:

\(num_i\) 記錄 \(i\) 的最小質因子的次數。

inline void sieve()
{
    d[1]=1;
    for(int i=2;i<=N;++i)
    {
        if(!flag[i]) prime[++cnt]=i,d[i]=2,num[i]=1;
        for(int j=1;j<=cnt&&i*prime[j]<=N;++j)
        {
            flag[i*prime[j]]=true;
            if(i%prime[j])
            {
                num[i*prime[j]]=1;
                d[i*prime[j]]=d[i]*2;
            }
            else
            {
                num[i*prime[j]]=num[i]+1;
                d[i*prime[j]]=d[i]/num[i*prime[j]]*(num[i*prime[j]]+1);
                break;
            }
        }
    }
}
線性篩 \(\sigma\)

由乘法原理得:

\[\sigma(n)=\prod_{i=1}^m\sum_{j=0}^{c_i}p_i^j \]

\(f\) 記錄約數和,\(g\) 記錄最小質因子 \(p\)\(\sum_{i=0}^{c}p^i\) 。則有:

  • 對於質數 \(p\) ,有 \(f(p)=2,g(n)=1+p\)
  • 對於 \(a,b\) 滿足 \(a \bot b\) ,且 \(ab\) 的最小質因子為 \(p\) ,有 \(f(ab)=f(a)f(b),g(ab)=\sum_{i=0}^{c}p^i\)
  • 對於質數 \(p\) 和合數 \(a\)\(p\)\(a\) 的最小質因子,有 \(g(pa)=g(a)\times p+1,f(pa)=f(a)\frac{g(pa)}{g(a)}\)
inline void sieve()
{
    f[1]=g[1]=1;
    for(int i=2;i<=N;++i)
    {
        if(!flag[i]) prime[++cnt]=i,f[i]=2,g[i]=1+i;
        for(int j=1;j<=cnt&&i*prime[j]<=N;++j)
        {
            flag[i*prime[j]]=true;
            if(i%prime[j])
            {
                f[i*prime[j]]=f[i]*f[prime[j]];
                g[i*prime[j]]=1+prime[j];
            }
            else
            {
                g[i*prime[j]]=g[i]*prime[j]+1;
                f[i*prime[j]]=f[i]/g[i]*g[i*prime[j]];
                break;
            }
        }
    }
}

尤拉函式

\[\varphi(n)=\sum_{i=1}^n[i\bot n] \]

有:

\[\varphi * {\rm{I}}={\rm{id}} \]

證明:

因為 \(\varphi\) 是積性函式,所以只需要證明 \(n=p^c\) 的情況,即證明:

\[(\varphi*{\rm{I}})(n)=\sum_{d|n}\varphi(d)={\rm{id}}(n) \]

因為 \(n=p^c\) 所以 \(d=1,p,p^2,p^3 \cdots,p^c\) ,將上式改為列舉 \(p\) 的次數:

\[\begin{align} \sum_{d|n}\varphi(d)&=\sum_{i=0}^c\varphi(p^i)\\ &=1+p^0(p-1)+p^1(p-1)+\cdots+p^{c-1}(p-1)\\ &=p^c\\ &={\rm{id}}(n) \end{align} \]

上面用到了尤拉函式的性質: \(\varphi(p^c)=p^{c-1}(p-1)\)

\(\varphi*{\rm{I}}={\rm{id}}\) 得證。

線性篩 \(\varphi\)
  • 對於質數 \(p\) ,有 \(\varphi(p)=p-1\)
  • 對於 \(a,b\) 滿足 \(a\bot b\) ,有 \(\varphi(ab)=\varphi(a)\varphi(b)\)
  • 對於質數 \(p\) 和數 \(a\) 滿足 \(p|a\) ,有 \(\varphi(pa)=\varphi(a)\times p\)

對於第三種情況,證明如下:

因為 \(p|a\) ,所以 \(a\) 包含了所有 \(pa\) 的質因子,則有:

\[\begin{align} \varphi(pa)&=p\times a\prod_{i=1}^m\frac{p_i-1}{p_i}\\ &=p\times\varphi(a) \end{align} \]

證畢。

inline void sieve()
{
	phi[1]=1;
	for(int i=2;i<=N;i++)
	{
		if(!flag[i]) prime[++cnt]=i,phi[i]=i-1;
		for(int j=1;j<=cnt&&prime[j]*i<=N;j++)
		{
			flag[prime[j]*i]=true;
			if(i%prime[j]==0)
			{
				phi[prime[j]*i]=phi[i]*prime[j];
				break;
			}
			else phi[prime[j]*i]=phi[i]*(prime[j]-1);
		}
	}
}

莫比烏斯函式

\[\mu(n)=\begin{cases}1 & n=1\\ 0 & \exist d>1:d^2|n \\ (-1)^{\omega(n)} & \text{otherwise}\end{cases} \]

其中 \(\omega(n)\) 表示 \(n\) 不同質因子個數。

有:

\[\sum_{d|n}\mu(d)=\epsilon(n) \iff \epsilon=\mu*{\rm{I}} \]

證明:

\(n=\prod_{i=1}^mp_i^{c_i},n'=\prod_{i=1}^mp_i\) ,則:

\[\begin{align} \sum_{d|n}\mu(d)&=\sum_{d|n'}\mu(d)\\ &=\sum_{i=0}^m{m \choose i}\times 1\times (-1)^i\\ &=(1+(-1))^k\\ &=\begin{cases}1 & k=0 \\ 0 & k \not =0\end{cases}\\ &=\begin{cases}1 & n=1 \\ 0 & n \not =1\end{cases}\\ &=\epsilon(n) \end{align} \]

這同時也證明了 \(\epsilon=\mu*{\rm{I}}\)

證畢。

與尤拉函式結合,有:

\[\varphi=\mu*{\rm{id}} \iff \varphi(n)=\sum_{d|n}d\cdot\mu(\frac{n}{d}) \]

證明:

\[\varphi*{\rm{I}}={\rm{id}} \iff \varphi*{\rm{I}}*\mu={\rm{id}}*\mu \iff \varphi=\mu*{\rm{id}} \]

上面用到了 \(\mu*{\rm{I}}=\epsilon\) 的結論。

證畢。

反演結論

\[[{\rm{gcd}}(i,j)=1] \iff \sum_{d|i,d|j}\mu(d) \]

線性篩 \(\mu\)
  • 對於質數 \(p\) ,有 \(\mu(p)=-1\)
  • 對於 \(a,b\) 滿足 \(a\bot b\) ,有 \(\mu(ab)=\mu(a)\mu(b)\)
  • 對於質數 \(p\) 和整數 \(a\) 滿足 \(p|a\) ,有 \(\mu(pa)=0\)
inline void sieve()
{
    mu[1]=1;
	for(int i=2;i<=N;++i)
	{
		if(!flag[i]) prime[++cnt]=i,mu[i]=-1;
		for(int j=1;j<=cnt&&i*prime[j]<=N;++j)
		{
			flag[i*prime[j]]=true;
			if(!(i%prime[j])) break;
			mu[i*prime[j]]=-mu[i];
		}
	}
}

參考資料:

莫比烏斯反演 - OI Wiki

篩法 - OI Wiki