前言
头都给队友们打烂了啊
这玩意还是简单易懂的啊qwq
似乎博客已经变成了笔记博客??
用途
求一类积性函数的前缀和
经典问题有求
μ
\mu
μ与
ϕ
\phi
ϕ的前缀和,本文将以这两个函数的前缀和为例
前置
狄利克雷卷积
两个函数
f
f
f和
g
g
g的狄利克雷卷积
f
∗
g
f*g
f∗g即为
(
f
∗
g
)
(
i
)
=
∑
d
∣
i
f
(
i
)
g
(
i
d
)
(f*g)(i)=\sum_{d|i}f(i)g(\frac{i}{d})
(f∗g)(i)=d∣i∑f(i)g(di)
玩法
假设当前我们需要求
f
(
x
)
f(x)
f(x)的前缀和
S
(
x
)
S(x)
S(x)
宇宙惯例,一般
n
n
n很大求不出来所以我们得做一些奇妙的操作
假设我们能弄出来一个简单的积性函数
g
(
x
)
g(x)
g(x)
对其做狄利克雷卷积得到函数
f
∗
g
f*g
f∗g
(
f
∗
g
)
(
i
)
=
∑
d
∣
i
f
(
i
)
g
(
i
d
)
(f*g)(i)=\sum_{d|i}f(i)g(\frac{i}{d})
(f∗g)(i)=d∣i∑f(i)g(di)
不妨设
(
f
∗
g
)
(
x
)
(f*g)(x)
(f∗g)(x)的前缀和函数为
p
r
e
(
x
)
pre(x)
pre(x),则有
p
r
e
(
x
)
=
∑
i
=
1
x
∑
d
∣
i
f
(
i
)
g
(
i
d
)
pre(x)=\sum_{i=1}^x\sum_{d|i}f(i)g(\frac{i}{d})
pre(x)=i=1∑xd∣i∑f(i)g(di)
把后面那个项提出来可以得到
p
r
e
(
x
)
=
∑
d
=
1
x
g
(
d
)
∗
∑
d
∣
i
f
(
i
d
)
pre(x)=\sum_{d=1}^{x}g(d)*\sum_{d|i}f(\frac{i}{d})
pre(x)=d=1∑xg(d)∗d∣i∑f(di)
p
r
e
(
x
)
=
∑
d
=
1
x
g
(
d
)
∗
∑
i
=
1
⌊
i
d
⌋
f
(
i
)
pre(x)=\sum_{d=1}^{x}g(d)*\sum_{i=1}^{\lfloor\frac{i}{d}\rfloor}f(i)
pre(x)=d=1∑xg(d)∗i=1∑⌊di⌋f(i)
p
r
e
(
x
)
=
∑
d
=
1
x
g
(
d
)
∗
S
(
⌊
i
d
⌋
)
pre(x)=\sum_{d=1}^{x}g(d)*S(\lfloor\frac{i}{d}\rfloor)
pre(x)=d=1∑xg(d)∗S(⌊di⌋)
我们不难得到下面的一个式子
g
(
1
)
S
(
n
)
=
∑
i
=
1
n
g
(
i
)
∗
S
(
⌊
n
i
⌋
)
−
∑
i
=
2
n
g
(
i
)
∗
S
(
⌊
n
i
⌋
)
g(1)S(n)=\sum_{i=1}^{n}g(i)*S(\lfloor\frac{n}{i}\rfloor)-\sum_{i=2}^{n}g(i)*S(\lfloor\frac{n}{i}\rfloor)
g(1)S(n)=i=1∑ng(i)∗S(⌊in⌋)−i=2∑ng(i)∗S(⌊in⌋)
注意到
S
(
i
)
=
∑
j
=
1
i
f
(
j
)
S(i)=\sum_{j=1}^{i}f(j)
S(i)=∑j=1if(j),考虑在狄利克雷卷积中,每个
g
(
d
)
g(d)
g(d)相乘的
f
(
i
d
)
f(\frac{i}{d})
f(di)中
i
d
\frac{i}{d}
di的值域在
[
1
,
n
i
]
[1,\frac{n}{i}]
[1,in]中,故不难得到其实前面是一个狄利克雷卷积和
那么式子可以变为
g
(
1
)
S
(
n
)
=
∑
i
=
1
n
(
f
∗
g
)
(
i
)
−
∑
i
=
2
n
g
(
i
)
∗
S
(
⌊
n
i
⌋
)
g(1)S(n)=\sum_{i=1}^n(f*g)(i)-\sum_{i=2}^{n}g(i)*S(\lfloor\frac{n}{i}\rfloor)
g(1)S(n)=i=1∑n(f∗g)(i)−i=2∑ng(i)∗S(⌊in⌋)
如果狄利克雷卷积的前缀和可以快速求出,且
g
g
g的前缀和也能快速求出
那么就可以对后面的
S
(
i
)
S(i)
S(i)数论分块,记忆化一发开始gank
如果能预处理前
n
2
3
n^{\frac{2}{3}}
n32的前缀和就能做到
O
(
n
2
3
)
O(n^{\frac{2}{3}})
O(n32)
筛 μ \mu μ
首先能知道一个结论就是
∑
d
∣
n
μ
(
d
)
=
[
n
=
=
1
]
\sum_{d|n}\mu(d)=[n==1]
d∣n∑μ(d)=[n==1]
那么我们构造
g
(
x
)
=
1
g(x)=1
g(x)=1
显然狄利克雷卷积的任意前缀和均为
1
1
1
那么就是要算
S
(
n
)
=
1
−
∑
i
=
2
n
g
(
i
)
∗
S
(
n
i
)
S(n)=1-\sum_{i=2}^{n}g(i)*S(\frac{n}{i})
S(n)=1−i=2∑ng(i)∗S(in)
那么直接做就好了
筛 ϕ \phi ϕ
又出来一个结论就是
∑
d
∣
n
ϕ
(
d
)
=
n
\sum_{d|n}\phi(d)=n
d∣n∑ϕ(d)=n
证明不妨考虑枚举
[
1
,
n
]
[1,n]
[1,n]中的数与
n
n
n的
g
c
d
gcd
gcd
同样构造
g
(
x
)
=
1
g(x)=1
g(x)=1
显然狄利克雷卷积的某个前缀和
i
i
i即为
i
∗
(
i
+
1
)
2
\frac{i*(i+1)}{2}
2i∗(i+1)
那么就是要算
S
(
n
)
=
(
1
+
n
)
∗
n
2
−
∑
i
=
2
n
g
(
i
)
∗
S
(
n
i
)
S(n)=\frac{(1+n)*n}{2}-\sum_{i=2}^{n}g(i)*S(\frac{n}{i})
S(n)=2(1+n)∗n−i=2∑ng(i)∗S(in)
同样直接做就好了
模板
bzoj3944 sum
即为筛
ϕ
\phi
ϕ与
μ
\mu
μ的前缀和
注意
2
31
−
1
2^{31}-1
231−1加一可能会爆
i
n
t
int
int
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(LL x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(LL x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
const int MAXN=5000005;
const int MAXM=50005;
int n,N;
int pr[MAXN],plen,mu[MAXN],phi[MAXN];
bool is[MAXN];
LL pre1[MAXN],pre2[MAXN];
void init()
{
phi[1]=1;mu[1]=1;
for(int i=2;i<MAXN;i++)
{
if(!is[i])pr[++plen]=i,mu[i]=-1,phi[i]=i-1;
for(int j=1;j<=plen&&i*pr[j]<MAXN;j++)
{
is[i*pr[j]]=true;
if(!(i%pr[j]))
{
mu[i*pr[j]]=0;phi[i*pr[j]]=phi[i]*pr[j];
break;
}
else mu[i*pr[j]]=-mu[i],phi[i*pr[j]]=phi[i]*(pr[j]-1);
}
}
for(int i=1;i<MAXN;i++)pre1[i]=pre1[i-1]+mu[i],pre2[i]=pre2[i-1]+phi[i];
}
bool vi1[2*MAXM],vi2[2*MAXM];
LL id1[2*MAXM];
int getid(int x){return x<=N?x:n/x+N;}
LL solvemu(int x)
{
if(x<MAXN)return pre1[x];
int u=getid(x);
if(vi1[u])return id1[u];
LL ret=1;vi1[u]=true;
for(int i=2,nxt;i<=x;i=nxt+1)
{
nxt=x/(x/i);
LL s=solvemu(x/i);
ret-=1LL*(nxt-i+1)*s;
if(nxt==x)break;
}
return id1[u]=ret;
}
LL id2[2*MAXM];
LL solvephi(LL x)
{
if(x<MAXN)return pre2[x];
int u=getid(x);
if(vi2[u])return id2[u];
LL ret=1LL*(x+1)*x/2;vi2[u]=true;
for(int i=2,nxt;i<=x;i=nxt+1)
{
nxt=x/(x/i);
LL s=solvephi(x/i);
ret-=1LL*(nxt-i+1)*s;
if(nxt==x)break;
}
return id2[u]=ret;
}
int main()
{
init();
int T=read();while(T--)
{
n=read();N=sqrt(n);
if(n<MAXN){pr1(pre2[n]),pr2(pre1[n]);continue;}
memset(vi1,false,sizeof(vi1));memset(vi2,false,sizeof(vi2));
pr1(solvephi(n));
pr2(solvemu(n));
}
return 0;
}