杜教筛
我们对于一个要求的数论函数 $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;
}