Loading

从积性函数到杜教筛

最近学习了积性函数的一些知识,口胡了这篇文章出来,由于本人学习的时间较短(半个月前才开始学,现在只切了十几道稍微有点质量的题),文章中难免出现纰漏,烦请各位 dalao 直接指出。

这篇文章篇幅稍长,综合性会比较强,一些细节可能不够准确,读者可以结合文末 Reference 部分的各篇博客,对各个知识点形成较深的理解。

积性函数

定义

  • 数论函数:即定义域为正整数的函数。

  • 积性函数:满足 \(\forall \gcd(p,q)=1,f(pq)=f(p)\times f(q)\) 的数论函数 \(f\)

  • 完全积性函数:满足 \(\forall a,b\in \mathbb{N}^+,f(ab)=f(a)\times f(b)\) 的数论函数 \(f\)(也就是没有互质的限制)。

一些常见的积性函数

\(n\) 的质因数分解为

\[n=\prod_{i=1}^k {p_i}^{a_i} \]

  • \(\gcd(x,n)\quad\) 其中 \(x\) 为常数

  • \(\gamma(n)=(-1)^k\qquad\)$\gamma$

  • \(d(n)=\prod_{i=1}^k (a_i+1)\quad n\) 的正因数个数

  • \(\sigma(n)=\prod_{i=1}^k \sum_{j=0}^{a_i} {p_i}^j\quad n\) 的正因数和 \(\qquad\)$\sigma$

  • \(\sigma_x(n)=\prod_{i=1}^k \sum_{j=0}^{a_i} {p_i}^{jx}\quad n\) 的正因数的 \(x\) 次方和

  • \(\varphi(n)=n\times \prod_{i=1}^k \frac{p_i-1}{p_i}\quad \le n\) 的正整数中与 \(n\) 互质的个数 \(\qquad\)$\varphi$

  • \[\mu(n)=\begin{cases}1&n=1\\0&\exists i,a_i\ge 2\\(-1)^k &\operatorname{otherwise}\end{cases} \]

$\mu$

一些常见的完全积性函数

  • \(1(n)=1\)

  • \(id(n)=n\)

  • \(id_x(n)=n^x\)

  • \(\epsilon(n)=[n=1]\quad\) 单位元 \(\qquad\)$\epsilon$

P.S.这些函数看起来可能很奇怪,但是在卷积和杜教筛中会很有用

积性函数的基本性质:\(f(1)=1\)

\(\because \forall a\in \mathbb{N}^+,\gcd(1,a)=1,\)

\(\therefore\) 由积性函数的定义,\(f(a\times 1)=f(a)\times f(1)\)

\(\therefore f(1)=1\)

线性筛

前置知识:欧拉筛

在欧拉筛中,每个合数都只会被自己的最小质因数筛掉一次,我们可以利用这个性质在筛质数时顺便把积性函数的值筛出来,像这样:

int f[],pr[],pcnt;bool vis[];

void sieve(){
	f[1]=1;//基本性质
	for(int i=2;i<=N;++i){
		if(!vis[i]) pr[++pcnt]=j,f[i]=(...);//n为质数时的函数值 
		for(int j=1;j<=pcnt&&i*pr[j]<=N;++j){
			vis[i*pr[j]]=1;
			if(i%pr[j]==0){
				f[i*pr[j]]=(...);//i与pr[j]不互质,特殊处理 
				break;
			}
			f[i*pr[j]]=f[i]*f[pr[j]];//积性函数的定义 
		} 
	}
}

拿几个常见函数练练手。

线性筛 \(\mu\)

\(n\in prime\) 时,\(\mu(n)=-1\)

当代码中 \(i\bmod pr_j=0\) 时,\({pr_j}^2 | i\times pr_j\),所以 \(\mu(i\times pr_j)=0\)

然后就有了这份代码。


void sieve(){
	mu[1]=1;
	for(int i=2;i<=N;++i){
		if(!vis[i]) pr[++pcnt]=j,mu[i]=-1;
		for(int j=1;j<=pcnt&&i*pr[j]<=N;++j){
			vis[i*pr[j]]=1;
			if(i%pr[j]==0){
				mu[i*pr[j]]=0;
				break;
			}
			mu[i*pr[j]]=mu[i]*mu[pr[j]];
		}
	}
}

线性筛 \(\varphi\)

\(n\in prime\) 时,\(\varphi(n)=n-1\)

当代码中 \(i\bmod pr_j=0\) 时,\(i\)\(i\times pr_j\) 的质因数 \(p_1,p_2,\cdots,p_k\) 相同(\(i\times pr_j\) 仅仅比 \(i\) 多了一个 \(pr_j\) 的次数),所以

\[\varphi(i)=i\times \prod_{i=1}^k \frac{p_i-1}{p_i} \]

\[\varphi(i\times pr_j)=i\times pr_j\times \prod_{i=1}^k \frac{p_i-1}{p_i} \]

所以 \(\varphi(i\times pr_j)=\varphi(i)\times pr_j\)

代码与线性筛 \(\mu\) 大同小异。

线性筛 \(d\)

\(n\in prime\) 时,\(d(n)=2\)

当代码中 \(i\bmod pr_j=0\) 时,\(i\)\(i\times pr_j\) 的质因数 \(p_1,p_2,\cdots,p_k\) 以及 除了 \(pr_j\) 的其它质因数的指数 \(a_i\) 仍然相同。

\(i\)\(pr_j\) 的指数为 \(x(x\ge 1)\),则 \(i\times pr_j\)\(pr_j\) 的次数为 \(x+1\),有

\[d(i)=(x+1)\prod_{i=1,p_i\ne pr_j}^k (a_i+1) \]

\[d(i\times pr_j)=(x+1+1)\prod_{i=1,p_i\ne pr_j}^k (a_i+1) \]

所以 \(d(i\times pr_j)=\frac{x+2}{x+1}\times d(i)\)


为了在线性筛的过程中能随时知道 \(x\) 的值,我们需要额外维护一个数组 \(num\)\(num_i\) 表示 \(i\) 含其最小质因子的次数

\(n\in prime\) 时,\(num_n=1\)

在内层循环中,对于枚举到的所有 \(i\times pr_j\)\(pr_j\) 都是其最小质因数(这里用到了欧拉筛的工作原理)。

当代码中 \(i\bmod pr_j=0\) 时,\(pr_j\) 同时也是 \(i\) 的最小质因子,所以 \(num_{i\times pr_j}=num_i+1\)

否则,\(i\) 不含 \(pr_j\) 这个质因子,\(num_{i\times pr_j}=1\)

代码也就不难写了。

void sieve(){
	d[1]=1;
	for(int i=2;i<=N;++i){
		if(!vis[i]) pr[++pcnt]=i,d[i]=2,num[i]=1;
		for(int j=1;j<=pcnt&&i*pr[j]<=N;++j){
			vis[i*pr[j]]=1;
			if(i%pr[j]==0){
				d[i*pr[j]]=d[i]/(num[i]+1)*(num[i]+2);
				num[i*pr[j]]=num[i]+1;
				break;
			}
			d[i*pr[j]]=d[i]*d[pr[j]];
			num[i*pr[j]]=1;
		}
	}
}

线性筛 \(\sigma\)

UVA1730 Sum of MSLCM

留给读者作思考题。


事实上,只要我们能知道 \(f(p^a)(p\in prime,a\ge 1)\) 的值,再套上一个 \(num\) 数组,就能筛出绝大多数的积性函数 \(f\)。这个东西在 这篇博客 的“线性筛一般积性函数”部分中有提到。

例题(学完莫反之后再来做):

P4449 于神之怒加强版

P6156 简单题

这两道题目都需要筛 通过莫反的一系列骚操作推出的 一个奇怪的积性函数,做完之后线性筛对你就不会成问题了。

狄利克雷卷积

定义

对于两个积性函数 \(f,g\),它们的狄利克雷卷积

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

性质

  • 交换律:\(f * g=g * f\)

  • 结合律:\((f* g)* h = f* (g* h)\)

(补一个函数加法的前置知识:\((f1+f2)(n)=f1(n)+f2(n)\)

  • 分配律:\(f* (g+h)=f* g + f* h\)

  • 单位元 \(\epsilon\)\(\forall f\in \text{积性函数},f* \epsilon =f\)

前三个性质的应用不多,这里就不证了。

我们把单位元的性质证一下。

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

\[\therefore (f * \epsilon)(n)=\sum_{d|n}f(d)\epsilon\left(\frac{n}{d}\right) \]

\[=f(n)\epsilon(1)+\sum_{d|n,d\ne n} f(d)\epsilon\left(\frac{n}{d}\right) \]

\[=f(n)\times 1+\sum_{d|n,d\ne n}f(d)\times 0=f(n), \]

\[\therefore f* \epsilon =f. \]

尤其重要的性质

两个积性函数 \(f,g\) 的狄利克雷卷积 \(h=f * g\) 仍然是积性函数

\[\forall \gcd(p,q)=1, \]

\[h(p)=\sum_{d1|p} f(d1)g\left(\frac{p}{d1}\right), \]

\[h(q)=\sum_{d2|q} f(d2)g\left(\frac{q}{d2}\right), \]

\[h(p)\times h(q)=\sum_{d1|p} f(d1)g\left(\frac{p}{d1}\right)\sum_{d2|q} f(d2)g\left(\frac{q}{d2}\right), \]

\[h(p)\times h(q)=\sum_{d1|p} \sum_{d2|q}f(d1)f(d2)g\left(\frac{p}{d1}\right)g\left(\frac{q}{d2}\right), \]

\[\because \gcd(p,q)=1,\therefore d1d2 \text{与} pq \text{的因数一一对应。设}T=d1d2. \]

\[\because d1|p,d2|q,\gcd(p,q)=1, \]

\[\therefore \gcd(d1,d2)=1,\text{同理},\gcd\left(\frac{p}{d1},\frac{p}{d2}\right)=1, \]

\[\therefore f(d1)f(d2)=f(d1d2)=f(T), \]

\[g\left(\frac{p}{d1}\right)g\left(\frac{q}{d2}\right)=g\left(\frac{pq}{d1d2}\right)=g\left(\frac{pq}{T}\right)(\text{积性函数定义}), \]

\[\therefore h(p)\times h(q)=\sum_{T|pq}f(T)g\left(\frac{pq}{T}\right)=h(pq)(\text{狄利克雷卷积定义}), \]

\[\therefore h\text{为积性函数。} \]

常用的函数卷积

  • \(1 * 1=d\)

\[(1 * 1)(n)=\sum_{k|n}1(k)1\left(\frac{n}{k}\right) \]

\[=\sum_{k|n}1=d(n). \]

一般地,\(\forall f\in \text{积性函数}\)

\[(f * 1)(n)=\sum_{d|n} f(d). \]

  • \(id_k * 1 = \sigma_k\)

\[(id_k * 1)(n)=\sum_{d|n}id_k(d)=\sigma_k(n). \]

  • \(\varphi * 1=id\)(欧拉反演)

\[(\varphi * 1)(n)=\sum_{d|n} \varphi(d)=n,\text{证明:} \]

\[\text{设}C_d=\{x:1\le x\le n,\gcd(x,n)=d\}, \]

\[\forall m,d|n,(d|m\text{且}m/d\le n/d\text{且}\gcd(n/d,m/d)=1)\Longleftrightarrow m\in C_d, \]

\[\because \text{满足}(d|m\text{且}m/d\le n/d\text{且}\gcd(n/d,m/d)=1)\text{的} m/d\text{的个数为}\varphi(n/d), \]

\[\therefore |C_d|=\varphi(n/d), \]

\[\therefore \sum_{d|n}|C_d|=\sum_{d|n} \varphi(n/d)=\sum_{d|n} \varphi(d); \]

\[\because \forall 1\le i\le n,\text{仅存在一个}d|n,i\in C_d, \]

\[\therefore \sum_{d|n}|C_d|=n, \]

\[\therefore \sum_{d|n}\varphi(d)=\sum_{d|n}|C_d|=n. \]

  • \(\mu* 1 =\epsilon\)(莫比乌斯反演)

\[(\mu * 1)(n)=\sum_{d|n} \mu(d)=[n=1],\text{证明:} \]

\[\text{设}n \text{质因数分解的形式为}\prod_{i=1}^k {p_i}^{a_i}, \]

\[\forall d|n,\text{仅当}\forall p\in prime,p^2\nmid d\text{时},\mu(d)\text{对答案有贡献},\text{即}d\text{的所有质因子的次数均为}1. \]

\[\text{对于含}x\text{个质因子的}d,\text{这类}d\text{总共有}\binom{k}{x}\text{个},\mu(d)=(-1)^x. \]

\[\therefore \sum_{d|n} \mu(d)=\sum_{i=0}^k \binom{k}{i}(-1)^i \]

\[=\sum_{i=0}^k \binom{k}{i}\times 1^{k-i}\times (-1)^i \]

\[\text{由二项式定理,}\sum_{i=0}^k \binom{k}{i}a^ib^{k-i}=(a+b)^k, \]

\[\therefore \sum_{d|n} \mu(d)=(1+(-1))^k=0^k \]

\[=\begin{cases}1&k=0\\0&\operatorname{otherwise}\end{cases}(\text{在组合数学中,总是定义}0^0=1) \]

\[\because k=0\leftrightarrow n=1, \]

\[\therefore \sum_{d|n} \mu(d)=[k=0]=[n=1]. \]

\[\text{不懂}0^0=1\text{也没有关系,} \]

\[\text{当}n\ne 1\text{时,}k\ne 0,\sum_{d|n}\mu(d)=0^k=0; \]

\[\text{当}n=1\text{时,}\sum_{d|n} \mu(d)=\mu(1)=1. \]

\[\therefore \sum_{d|n} \mu(d)=[n=1]. \]

  • \(\mu * id = \varphi\)

\[\mu * id =\mu * (\varphi * 1) \]

\[=(\mu * 1) * \varphi \]

\[=\epsilon * \varphi=\varphi. \]

  • \(\mu * d=1\)

\[\mu * d=\mu * (1 * 1) \]

\[=(\mu * 1)* 1 \]

\[=\epsilon * 1=1. \]


这几条最好熟悉一下,尤其是 \(\varphi * 1=id\)\(\mu* 1 =\epsilon\),在推柿子时可能会用到,记下它们也对杜教筛有帮助。

杜教筛

可以以 \(O(n^\frac{2}{3})\) 的复杂度求出 \(S(n)=\sum_{i=1}^n f(i)\),其中 \(f\)某些积性函数,同时能够顺便求出 \(O(\sqrt{n})\) 个满足 \(i<n\)\(S(i)\)

思路

铺垫了这么多,总是要用上的是吧。 所以我们 凭感觉 构造出两个函数 \(g,h\)这两个函数的前缀和要很好算,同时满足

\[f * g=h \]

我们对 \(h\) 求前缀和:

\[\sum_{i=1}^n h(i)=\sum_{i=1}^n \sum_{d|i}g(d)f\left(\frac{i}{d}\right) \]

\[=\sum_{d=1}^n g(d) \sum_{i=1}^n [d|i] f\left(\frac{i}{d}\right) \]

\[=\sum_{d=1}^n g(d) \sum_{i=1}^{n/d} f(i)=\sum_{i=1}^d g(d)S(n/d) \]

拆出一个 \(S(n)\)

\[\sum_{i=1}^n h(i)=g(1)S(n)+\sum_{d=2}^n g(d)S(n/d) \]

\[g(1)S(n)=\left(\sum_{i=1}^n h(i)\right)-\sum_{d=2}^n g(d)S(n/d) \]

这就是杜教筛用到的套路式了。

我们可以很快地算出 \(h\) 的前缀和,

对于 \(\sum_{d=2}^n g(d)S(n/d)\),我们直接整除分块,快速算出 \(g\) 的前缀和,\(S(n/d)\) 直接递(甩)归(锅)计算(所以一次套上记忆化的杜教筛可以求出 \(O(\sqrt{n})\) 个值)。

现在开始写代码,复杂度为

\[T(n)=\sum_{i=1}^{\sqrt{n}} O(\sqrt{i})+O\left(\sqrt{\frac{n}{i}}\right)=O(n^\frac{3}{4}) \]

我们可以进行优化。

把这篇博客从前往后翻,还有什么知识点没用到呢?

线性筛!

我们可以提前线性筛出 \(i\in[1,m]\)\(S(i)\),在杜教筛调用到的时候直接返回。

复杂度为

\[T(n)=\sum_{i=1}^{n/m}\sqrt{\frac{n}{i}}=O\left(\frac{n}{\sqrt{m}}\right) \]

一般来说,我们取 \(m=n^\frac{2}{3}\),线性筛+杜教筛的复杂度为

\[O(m)+O\left(\frac{n}{\sqrt{m}}\right)=O(n^\frac{2}{3})+O(n^\frac{2}{3})=O(n^\frac{2}{3}). \]

举几个栗子。

P4213 【模板】杜教筛(Sum)

杜教筛 \(\mu\)

我们知道 \(\mu * 1 = \epsilon\),所以设 \(g=1,h=\epsilon\)

对照套路式,有

\[S(n)=\sum_{i=1}^n \epsilon(i)-\sum_{d=2}^n 1(d)S(n/d) \]

\[=1-\sum_{d=2}^n S(n/d). \]

然后就可以打代码了。

void sieve(){
   ...
}

unordered_map<int,int> smu;//unordered_map 用的是哈希表,虽然常数大,但好歹是 O(1) 的

int Smu(int n){
	if(n<=N) return mu[n];//线性筛的结果
	if(smu[n]) return smu[n];//记忆化
	int res=1;
	for(ui i=2,j;i<=n;i=j+1){
		j=n/(n/i);
		res-=(j-i+1)*Smu(n/i);
	}
	return smu[n]=res;
}

杜教筛 \(\varphi\)

与杜教筛 \(\mu\) 几乎没有区别。

杜教筛 \(f(n)=i\times \varphi(i)\)

我们不能直接套了。

但是我们根据自己对狄利克雷卷积的理解\(\varphi\) 联想到 \(\sum_{d|n} \varphi(d)=n\),不难构造出

\[g=id,h=id_2 \]

\[(f * g)(n)=\sum_{d|n} d\times \varphi(d)\times \frac{n}{d} \]

\[=n\times \sum_{d|n} \varphi(d)=n^2=h(n). \]

是不是很神奇!

\(g\) 的前缀和 \(S_g(n)=\frac{n(n+1)}{2}\)\(h\) 的前缀和 \(S_h(n)=\frac{n(n+1)(2n+1)}{6}\)

代码也就呼之欲出了:

void sieve(){
	//f(i)=i*phi(i),很容易筛 
}

int S(int n){
	if(n<=N) return s[n];
	if(ss[n]) return ss[n];
	int res=n*(n+1)*(n<<1|1)/2;
	for(int i=2;i<=n;i=j+1){
		j=n/(n/i);
		res-=(j*(j+1)/2-i*(i-1)/2)*S(n/i);
	}
	return ss[n]=res;
}

所以,杜教筛构造出函数之后代码很容易打,但是构造基本只能靠感觉,了解一些常见的函数的狄利克雷卷积对杜教筛的构造会有帮助。


建议直接切掉:

P6055 [RC-02] GCD

P3768 简单的数学题

P1587 [NOI2016] 循环之美

写在最后

花了一天肝这篇博客,总算是写完了。

韩信带净化,这篇文章是我个人对积性函数的理解,有些地方可能不太到位,如果有些地方看不懂的话,强烈推荐 Reference 的前两篇 @mango09 的博客,讲得很清晰。

最后的最后,臭不要脸地 宣传一波本人莫反的博客 (你看例题里面这么多题都用到了莫反,确定不看一眼吗)

完结撒花~~~

Reference

posted @ 2022-02-26 16:10  Albertvαn  阅读(56)  评论(0编辑  收藏  举报