[学习笔记] 杜教筛

好久以前就写过了,但是现在才搞懂原理。

前置知识

首先称一个函数 \(f(x)\)积性函数 ,当且仅当对于任意两个互质的数 \(a,b\) ,有:

\[f(ab)=f(a)f(b) \]

更特殊地,称一个函数 \(f(x)\)完全积性函数 ,当且仅当对于任意 \(a,b\) ,有:

\[f(ab)=f(a)f(b) \]

常见的积性函数有 \(\mu,\varphi,\sigma,d\) ,完全积性函数有:\(\epsilon,I,id\)

\(\epsilon(n)=[n=1],I(n)=1,id(n)=n\)

对于两个函数 \(f,g\) ,定义他们的 迪利克雷卷积 为:

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

对于上面我们已经给出函数,有这样一些卷积关系是:

\[\mu*I=\epsilon \]

\[\varphi*I=id \]

\[\mu*id=\varphi \]

补充一个东西,\(\sum_{x|n}\varphi(x)=n\) 的证明,考虑两个互质的数 \(m,n\) ,有:

\[\sum_{x|n}\sum_{y|m}\varphi(x)\varphi(y)=\sum_{x|n}\sum_{y|m}\varphi(xy)=\sum_{x|nm}\varphi(x) \]

这说明了 \(f(x)=\sum_{x|n}\varphi(x)\) 是一个积性函数,对于质数有 \(f(p_i^{k_i})=p_i^{k_i}\) ,那么 \(f(n)=n\)

杜教筛

他是用来解决这样一个问题:$$\sum_{i=1}^nf(i)=S(n)$$ ,做法是找一个 辅助函数 \(g\) ,也就是我们先求出 \(f*g\) 的前缀和,再算 \(f\) 的前缀和,选取 \(g\) 的标准就是 \(f*g\)\(g\) 的前缀和都是很好算的 ,先来推柿子:

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

然后套路地枚举 \(d\) (这种东西莫比乌斯反演的时候都见惯了):

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

考虑 用前缀和来表示单个项 \(g(1)S(n)\) ,因为前缀和是好算的:

\[g(1)S(n)=\sum_{i=1}^ng(i)S(\frac{n}{i})-\sum_{i=2}^ng(i)S(\frac{n}{i})=\sum_{i=1}^n(f*g)(i)-\sum_{i=2}^ng(i)S(\frac{n}{i}) \]

假定前面的项是好算的,后面的项可以用数论分块来解决,容易发现我们得到了一个递归的问题。

模板题

[模板]杜教筛

\(\mu\) 的前缀和

考虑到莫比乌斯反演的那个柿子:\(\mu*I=\epsilon\) ,令 \(f=\mu,g=I,f*g=\epsilon\)

ll get_mu(int n)
{
	if(n<=N) return mu[n];//这里是预处理的mu
	if(smu[n]) return smu[n];//这里是map记忆化
	ll ans=1;//f*g的前缀和
	for(int l=2,r;r<inf && l<=n;l=r+1)//数论分块
	{//这道题要卡 inf,因为可能加爆 
		r=n/(n/l);
		ans-=(r-l+1)*get_mu(n/l);//I的求和是r-l+1,然后递归
	}
	return smu[n]=ans;//得到答案
}

\(\varphi\) 的前缀和

考虑到欧拉反演的柿子:\(\varphi*I=id\) ,令 \(f=\varphi,g=I,f*g=id\)

\(id\) 的前缀和特别好算,就是:\(\frac{n(n+1)}{2}\)

ull get_ph(int n)
{
	if(n<=N) return phi[n];//这里是预处理的phi
	if(sph[n]) return sph[n];//map记忆化
	ull ans=(ull)n*(n+1ll)/2;//要开ull
	for(int l=2,r;r<inf && l<=n;l=r+1)//数论分块
	{
		r=n/(n/l);
		ans-=(r-l+1)*get_ph(n/l);//I的求和是r-l+1,然后递归
	}
	return sph[n]=ans;//得到答案
}

扩展:\(\varphi\cdot id\) 的前缀和

需要说明一下:\(\varphi\cdot id=\sum_{i=1}^n\varphi(i)i\)

\(f=\varphi\cdot id\)\(g=id\)\(f*g=(\varphi\cdot i)*i\) ,我们来看这个东西的前缀和好不好算:

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

最后一步是欧拉反演,所以他的前缀和是 \(\frac{n(n+1)(2n+1)}{6}\)

现在做一个小总结吧,杜教筛的关键是找辅助函数,让前缀和变得好算。

其他例题

简单的数学题

这两个是一类题,都是函数结构递归,然后杜教筛处理边界:循环之美,DZY Loves Math IV

posted @ 2021-01-31 10:32  C202044zxy  阅读(74)  评论(0编辑  收藏  举报