浅谈杜教筛

来重温一下杜教筛,由于生物历史会考,有一阵子没写了……

狄利克雷卷积

有两个函数\(f,g,\) 它们的狄利克雷卷积为 \((f*g)=\sum_{d|n}f(d)g(\frac{n}{d}).\)

由定义得,狄利克雷卷积满足交换律,结合律。

常见狄利克雷卷积:

\(\mu*id=\varphi,\mu*1=\varepsilon,id*1=\rho,1*1=d,d\)函数是约数个数.

杜教筛

考虑求\(f(i)\)的前缀和。令\(h(i)=f*g.S(i)=\sum_i f(i).\)

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

枚举\(d:\)

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

考虑\(g(1)S(n)\)如何求。由上式得:

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

求出\(g(1)S(n)\)后,除以\(g(1)\)即可得到结果。

那么,根据上面柿子可以得到应用杜教筛的条件:\(g,h\)函数的前缀和都很好求。

\(\mu\)的前缀和

我们知道,\(\mu*1=\varepsilon.\)\(f=\mu,g=1,h=\varepsilon.\)

\(\varepsilon\)的前缀和\(=1,g\)的前缀和 \(=n.\)

从而我们可以在\(O(n^{\frac{3}{4}})\)的时间中求出。

如果我们线性筛出前 \(n^{\frac{2}{3}}\) 的函数,我们就可以在\(O(n^{\frac{2}{3}})\)的时间中求得结果。

证明上面\(O(n^{\frac{3}{4}})\)的复杂度:

求出\(S(n)\)需要\(\sqrt n\)\(S(\frac{n}{i})\)的不同取值。结合数论分块复杂度:

\[O=\sum_{i=1}^{\sqrt n}\sqrt i+\sqrt{\frac{n}{i}}=n^{\frac{3}{4}}. \]

筛好前\(m\)个值,上面\(\sum\)上限会变成\(\frac{n}{m}.\)筛出前\(n^{\frac{2}{3}}\)即可将时间复杂度降为\(O(n^{\frac{2}{3}}).\)

\(\varphi\)的前缀和

\(\varphi*\varepsilon=id,f=\varphi,g=\varepsilon,h=id.\sum id=\frac{n*(n+1)}{2}.\)同上面求即可。

上面加起来就是模板.

\(Other\)

\(\sum \varphi(i)·i.\)

\(f=\sum \varphi*i,g=id,h=\sum_{d|n} \varphi(d)*d*\frac{n}{d} =n^2.\)同上面求即可。

上面的模板题中,\(\varphi\)也可以用莫比乌斯反演求出来。

\(\sum_{i=1}^n \varphi(i)=\sum_{i=1}^n \sum_{j=1}^i gcd(i,j)=1\)

去掉\(j<=i\)的限制,即为:

\(\sum_{i=1}^n \sum_{j=1}^n gcd(i,j)=1=\sum_{i=1}^n \sum_{j=1}^n \sum_{d|gcd(i,j)}\mu(i).=\sum_{d=1}^n \mu(d) (\frac{n}{d})^2.\)

求出上面式子,得出它的一半即可。

模板题代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN=2e6+10;
bitset<MAXN+10>vis;
int p[MAXN+10],cnt,mu[MAXN+10],phi[MAXN+10];
typedef long long ll;
void predo(){
	mu[1]=1;phi[1]=1;
	for(int i=2;i<=MAXN;++i){
		if(!vis[i])p[++cnt]=i,phi[i]=i-1,mu[i]=-1;
		for(int j=1;j<=cnt&&i*p[j]<=MAXN;++j){
			vis[i*p[j]]=1;
			if(i%p[j]==0){
				phi[i*p[j]]=phi[i]*p[j];
				break;
			}
			phi[i*p[j]]=phi[i]*(p[j]-1);
			mu[i*p[j]]=-mu[i];
		}
	}
	for(int i=1;i<=MAXN;++i)mu[i]+=mu[i-1],phi[i]+=phi[i-1];
}
map<int,int>M,P;
ll GetM(int n){
	if(n<=MAXN)return mu[n];
	if(M.count(n))return M[n];
	ll res=1;
	for(ll l=2,r;l<=n;l=r+1){
		r=(n/(n/l));
		res-=(r-l+1)*GetM(n/l);
	}
	return M[n]=res;
}
ll GetP(int n){
	if(n<=MAXN)return phi[n];
	if(P.count(n))return P[n];
	ll res=(n*(n+1))/2;
	for(ll l=2,r;l<=n;l=r+1){
		r=(n/(n/l));
		res-=(r-l+1)*GetP(n/l);
	}
	return P[n]=res;
}
signed main(){
	predo(); 
	int T;scanf("%lld",&T);while(T--){
		int x;
		scanf("%lld",&x);
		printf("%lld %lld\n",GetP(x),GetM(x));
	}
	return 0;
}
posted @ 2020-07-26 10:50  Refined_heart  阅读(171)  评论(0编辑  收藏  举报