我们对于一个要求的数论函数 $f(x)$,定义 $S(n)=\sum_{i=1}^nf(x)$

然后我们考虑构造一个 $S(n)$ 关于 $S(\lfloor\frac{n}{i}\rfloor)$ 的一个递推式子。

我们发现,对于任意的一个数论函数 $g(x)$ ,我们有:

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

然后我们考虑先枚举 $d$

\[=\sum_{d=1}^{n}\sum_{k=1}^{kd\le n}g(d)f(\frac{kd}{d})\] \[=\sum_{d=1}^{n}\sum_{k=1}^{\lfloor\frac{n}{d}\rfloor}g(d)f(k)\] \[=\sum_{d=1}^{n}g(d)S(\lfloor\frac{n}{d}\rfloor)\]

所以由上面的式子,可以得到一个杜教筛的核心公式:

\[g(1)S(n)=\sum_{i=1}^{n}(f\times g)(i)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)\]

这样我们就可以求一些数论函数的前缀和了。

我们举两个例子:一个 $\mu$ 一个 $\varphi$

我们先以 $\mu$ 为例。

因为 $\mu \times 1=e$,我们把 $f$ 代入 $\mu$ , 把 $g$ 代入 $1$,可得:

\[S(n)=\sum_{i=1}^{n}e(i)-\sum_{i=2}^{n}S(\lfloor\frac{n}{i}\rfloor)\] \[=1-\sum_{i=2}^nS(\lfloor\frac{n}{i}\rfloor)\]

然后 $\varphi$ 同理可以由 $\varphi\times1=id$ 得到:

\[S(n)=\sum_{i}^{n}id(i)-\sum_{i=2}^nS(\lfloor\frac{n}{i}\rfloor)\] \[S(n)=\frac{(n+1)n}{2}-\sum_{i=2}^nS(\lfloor\frac{n}{i}\rfloor)\]

但是同时,我们还可以用莫比乌斯反演,以达到只需 $\mu$ 的前缀和即可。

\[S(n)=\frac{1}{2}(\sum_{i=1}^n\mu(i)\lfloor\frac{n}{i}\rfloor^2-1)+1\]

附上 模板题 代码

#include<bits/stdc++.h>
#define ll long long
#define db double
#define filein(a) freopen(#a".in","r",stdin)
#define fileot(a) freopen(#a".out","w",stdout)
#define sky fflush(stdout)
template<class T>
inline void read(T &s){
	s=0;char ch=getchar();bool f=0;
	while(ch<'0'||'9'<ch) {if(ch=='-') f=1;ch=getchar();}
	while('0'<=ch&&ch<='9') {s=s*10+(ch^48);ch=getchar();}
	if(ch=='.'){
		db p=0.1;ch=getchar();
		while('0'<=ch&&ch<='9') {s=s+(ch^48)*p;p*=0.1;ch=getchar();};
	}
	s=f?-s:s;
}
const int N23=1664510+3;
std::vector<int>pri;
int mu[N23];
bool vis[N23];
const int Sz=1145141;
struct hash_map{
	std::vector<int>head,nxt;
	struct node{
		ll v,w;
	};
	std::vector<node>to;
	hash_map(){
		head.resize(Sz+3,-1);
	}
	inline ll & operator [](ll x){
		int u=x%Sz;
		for(int i=head[u];~i;i=nxt[i]){
			int v=to[i].v;
			if(v==x){
				return to[i].w;
			}
		}
		nxt.push_back(head[u]);
		head[u]=to.size();
		to.push_back({x,0});
		return to[to.size()-1].w;
	}
}Smu;
inline void Euler(int n){
	Smu[1]=vis[1]=mu[1]=1;
	for(int i=2;i<=n;++i){
		if(!vis[i]){
			pri.push_back(i);
			mu[i]=-1;
		}
		for(auto it:pri){
			if(i*it>n) break;
			vis[i*it]=1;
			if(i%it){
				mu[i*it]=-mu[i];
			}else{
				mu[i*it]=0;
				break;
			}
		}
	}
	for(int i=2;i<=n;++i){
		Smu[i]=Smu[i-1]+mu[i];
	}
}
inline ll Sum_mu(ll n){
	if(n<N23) return Smu[n]; 
	if(Smu[n]) return Smu[n];
	ll res=0;
	for(ll l=2,r;l<=n;l=r+1){
		r=n/(n/l);
		res+=(r-l+1)*Sum_mu(n/l);
	}
	return Smu[n]=(1ll-res);
}
inline ll Sum_phi(ll n){
	ll res=0;
	for(ll l=1,r;l<=n;l=r+1){
		r=n/(n/l);
		res+=(Sum_mu(r)-Sum_mu(l-1) )*(n/l)*(n/l);
	}
	return (res-1)/2+1;
}
int main(){
	filein(a);fileot(a);
	Euler(N23-3);
	int T;read(T);
	while(T--){
		ll x;read(x);
		printf("%lld %lld\n",Sum_phi(x),Sum_mu(x) );
	}
	return 0;
}