积性函数
1、积性函数:任意互素的两个数m、n,满足f(mn)=f(m)f(n)
常见积性函数:
φ
,
μ
,
σ
,
d
φ,μ,σ,d
φ,μ,σ,d
φ:欧拉函数
μ:莫比乌斯函数
d:约束个数函数
d
=
∑
d
∣
n
1
d=\sum_{d|n}1
d=∑d∣n1
σ:约束和函数
σ
(
n
)
=
∑
d
∣
n
d
σ(n)=\sum_{d|n}d
σ(n)=∑d∣nd
2、完全积性函数:任意两个数m、n,满足f(mn)=f(m)f(n)
常见完全积性函数:
ϵ
,
I
,
i
d
ϵ,I,id
ϵ,I,id
ϵ
ϵ
ϵ:元函数
ϵ
(
n
)
=
[
n
=
1
]
ϵ(n)=[n=1]
ϵ(n)=[n=1]
I
I
I:恒等函数
I
(
n
)
=
1
I(n)=1
I(n)=1
i
d
id
id:单位函数
i
d
(
n
)
=
n
id(n)=n
id(n)=n
狄利克雷卷积
定义:两个数论函数 f 和 g 的卷积为
(
f
∗
g
)
(
n
)
=
∑
d
∣
n
f
(
d
)
g
(
n
d
)
(f*g)(n)=\sum_{d|n}f(d)g(\frac nd)
(f∗g)(n)=∑d∣nf(d)g(dn)
性质:和乘法差不多,满足交换律、结合律、分配律
1、交换律:交换的顺序,只是枚举的约数的顺序出现变化,每个约数的贡献不变
2、元函数:
f
∗
ϵ
=
f
f*\epsilon =f
f∗ϵ=f
欧拉函数
定义:
φ
(
n
)
\varphi (n)
φ(n)指小于等于n且与n互素的正整数的个数
公式:
φ
(
n
)
=
n
∏
i
=
1
k
(
1
−
1
p
i
)
\varphi(n)=n \prod_{i=1}^{k} (1-\frac 1{p_i})
φ(n)=n∏i=1k(1−pi1),k为不同的质因子的个数
性质:
1、当n>2时,
φ
(
n
)
\varphi (n)
φ(n)为偶数
2、当n>1时,小于n的数中与n互质的数的总和是:
φ
(
n
)
n
2
\frac {\varphi (n) n}{2}
2φ(n)n
3、n的所有因子的欧拉函数之和等于n:
∑
d
∣
n
φ
(
d
)
=
n
\sum_{d|n}\varphi (d)=n
∑d∣nφ(d)=n
欧拉函数的三种求法
1、直接求欧拉函数,也可以先筛出素数,然后用素数去化简
ll euler(ll n)
{
ll ret=n,a=n;
for(ll i=2;i*i<=a;++i)
{
if(a%i==0)
{
ret=ret/i*(i-1);
while(a%i==0)
a/=i;
}
}
if(a>1)
ret=ret/a*(a-1);
return ret;
}
2、埃氏筛
int phi[maxn];
void euler(int n)
{
for(int i=1;i<=n;++i)
phi[i]=i;
for(int i=2;i<=n;++i)
{
//相等表示i是质数。不相等,说明是合数,已经被更新过了
if(phi[i]==i)
{
//遍历i的倍数,i是质因子,据公式更新
for(int j=i;j<=n;j+=i)
phi[j]=phi[j]/i*(i-1);
}
}
}
3、欧拉筛求欧拉函数
const int N=1e5;
int visit[N+10],phi[N+10],prime[N+10],cnt;
void euler()
{
phi[1]=1,cnt=0; //1要特判
for (int i=2;i<=N;i++)
{
if(!visit[i]) //这代表i是质数
{
prime[++cnt]=i;
phi[i]=i-1;
}
for (int j=1;j<=cnt&&prime[j]*i<=N;j++)
{
visit[i*prime[j]]=1; //把这个合数标记掉
if (i%prime[j]==0)
{
//若prime[j]是i的质因子,据计算公式,i已经包括i*prime[j]的所有质因子
phi[i*prime[j]]=phi[i]*prime[j];
break; //break用于这样能保证每个数只会被自己最小的因子筛掉一次
}
else //与质数不是倍数关系,就是互质
phi[i*prime[j]]=phi[i]*phi[prime[j]]; //积性函数
}
}
}
不带注释
const int N=1e5;
int visit[N+10],phi[N+10],prime[N+10],cnt;
void euler()
{
phi[1]=1,cnt=0;
for (int i=2;i<=N;i++)
{
if(!visit[i])
{
prime[++cnt]=i;
phi[i]=i-1;
}
for (int j=1;j<=cnt&&prime[j]*i<=N;j++)
{
visit[i*prime[j]]=1;
if (i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else phi[i*prime[j]]=phi[i]*phi[prime[j]];
}
}
}
莫比乌斯函数
定义:每一个n可以分解为:
n
=
p
1
k
1
p
2
k
2
…
p
s
k
s
n=p_1^{k_1}p_2^{k_2}\dots p_s^{k_s}
n=p1k1p2k2…psks
μ
(
n
)
=
{
1
(
n
=
1
)
0
(
∃
k
i
≥
2
)
(
−
1
)
s
(
∀
k
i
=
1
)
\mu(n)=\begin{cases} 1 &(n=1) \\ 0 &(\exists k_i \ge2)\\ (-1)^s &(\forall k_i=1) \end{cases}
μ(n)=⎩⎪⎨⎪⎧10(−1)s(n=1)(∃ki≥2)(∀ki=1)
性质:
1、
∑
d
∣
n
u
(
d
)
=
[
n
=
1
]
\sum_{d|n}u(d)=[n=1]
∑d∣nu(d)=[n=1]
2、
∑
d
∣
n
μ
(
d
)
n
d
=
φ
(
n
)
\sum_{d|n} \mu(d) \frac nd=\varphi(n)
∑d∣nμ(d)dn=φ(n)
证明:利用欧拉函数的性质:
∑
d
∣
n
φ
(
d
)
=
n
\sum_{d|n}\varphi (d)=n
∑d∣nφ(d)=n
写成卷积形式:
φ
∗
I
=
i
d
\varphi *I=id
φ∗I=id
化简:
φ
∗
I
∗
μ
=
i
d
∗
μ
\varphi *I*\mu=id*\mu
φ∗I∗μ=id∗μ
⟶
\longrightarrow
⟶
φ
∗
ϵ
=
i
d
∗
μ
\varphi *\epsilon=id*\mu
φ∗ϵ=id∗μ
φ
(
n
)
=
∑
d
∣
n
u
(
d
)
i
d
(
n
d
)
=
∑
d
∣
n
u
(
d
)
n
d
\varphi (n)=\sum_{d|n}u(d)id(\frac nd)=\sum_{d|n}u(d)\frac nd
φ(n)=∑d∣nu(d)id(dn)=∑d∣nu(d)dn
线性筛莫比乌斯函数
const int N=5e4+5;
int prime[maxn],visit[maxn];
int mu[maxn],cnt;
void Mobius()
{
memset(visit,0,sizeof(visit));
memset(mu,0,sizeof(mu));
cnt=0,mu[1]=1,visit[1]=1;
for(int i=2;i<N;++i)
{
if(!visit[i])
prime[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&i*prime[j]<N;++j)
{
visit[i*prime[j]]=1;
if(i%prime[j]==0)
break;
mu[i*prime[j]]=-mu[i];
}
}
}
莫比乌斯反演
形式一:设f(n)是一个任意的函数,
F
(
n
)
=
∑
d
∣
n
f
(
d
)
F(n)=\sum_{d|n}f(d)
F(n)=∑d∣nf(d)
反演可得:
f
(
n
)
=
∑
d
∣
n
μ
(
d
)
F
(
n
d
)
f(n)=\sum_{d|n}\mu (d)F(\frac nd)
f(n)=d∣n∑μ(d)F(dn)
证明:
F
(
n
)
=
∑
d
∣
n
f
(
d
)
=
f
∗
I
=
F(n)=\sum_{d|n}f(d)=f*I=
F(n)=∑d∣nf(d)=f∗I=
F
∗
μ
=
f
∗
I
∗
μ
=
f
∗
(
I
∗
u
)
F*\mu =f*I*\mu=f*(I*u)
F∗μ=f∗I∗μ=f∗(I∗u)
利用性质:
∑
d
∣
n
u
(
d
)
=
[
n
=
1
]
\sum_{d|n}u(d)=[n=1]
∑d∣nu(d)=[n=1]
因此:
I
∗
μ
=
ϵ
I*\mu =\epsilon
I∗μ=ϵ
f
∗
(
I
∗
μ
)
=
f
∗
ϵ
=
f
=
F
∗
μ
=
∑
d
∣
n
u
(
d
)
F
(
n
d
)
f*(I*\mu)=f*\epsilon=f=F* \mu=\sum_{d|n}u(d)F(\frac nd)
f∗(I∗μ)=f∗ϵ=f=F∗μ=d∣n∑u(d)F(dn)
形式二:设f(n)是一个任意的函数,
F
(
n
)
=
∑
n
∣
d
f
(
d
)
F(n)=\sum_{n|d}f(d)
F(n)=∑n∣df(d)
反演可得:
f
(
n
)
=
∑
n
∣
d
μ
(
d
n
)
F
(
d
)
f(n)=\sum_{n|d}\mu (\frac dn)F(d)
f(n)=n∣d∑μ(nd)F(d)
杜教筛
用途:计算积性函数的前缀和,时间复杂度为
O
(
n
2
3
)
O(n^{\frac 23})
O(n32)
1、需要计算:
∑
i
=
1
n
f
(
i
)
\sum_{i=1}^nf(i)
∑i=1nf(i)
2、构造两个积性函数h和g满足:
h
=
f
∗
g
h=f*g
h=f∗g
3、推导:先计算
∑
i
=
1
n
h
(
i
)
\sum_{i=1}^n h(i)
∑i=1nh(i),设
S
(
n
)
S(n)
S(n)为
f
(
i
)
f(i)
f(i)前缀和
∑ i = 1 n h ( i ) = ∑ i = 1 n ∑ d ∣ i g ( d ) f ( i d ) \sum_{i=1}^n h(i)=\sum_{i=1}^n\sum_{d|i}g(d)f(\frac id) i=1∑nh(i)=i=1∑nd∣i∑g(d)f(di)
= ∑ d = 1 n g ( d ) ∑ i = 1 n d f ( i ) =\sum_{d=1}^n g(d)\sum_{i=1}^{\frac nd}f(i) =d=1∑ng(d)i=1∑dnf(i)
= ∑ d = 1 n g ( d ) S ( n d ) =\sum_{d=1}^n g(d) S(\frac nd) =d=1∑ng(d)S(dn)
= g ( 1 ) S ( n ) + ∑ d = 2 n g ( d ) S ( n d ) =g(1)S(n)+\sum_{d=2}^n g(d) S(\frac nd) =g(1)S(n)+d=2∑ng(d)S(dn)
因此可得:
g
(
1
)
S
(
n
)
=
∑
i
=
1
n
h
(
i
)
−
∑
d
=
2
n
g
(
d
)
S
(
n
d
)
g(1)S(n)=\sum_{i=1}^n h(i) - \sum_{d=2}^n g(d) S(\frac nd)
g(1)S(n)=i=1∑nh(i)−d=2∑ng(d)S(dn)
例一:求
S
(
n
)
=
∑
i
=
1
n
μ
(
i
)
S(n)=\sum_{i=1}^n\mu(i)
S(n)=∑i=1nμ(i)
我们很容易想到:
μ
∗
I
=
ϵ
\mu*I=\epsilon
μ∗I=ϵ,对
ϵ
\epsilon
ϵ求求前缀和就是1
g
(
1
)
S
(
n
)
=
∑
i
=
1
n
h
(
i
)
−
∑
d
=
2
n
g
(
d
)
S
(
⌊
n
d
⌋
)
g(1)S(n)=\sum_{i=1}^n h(i) - \sum_{d=2}^n g(d) S(\lfloor \frac nd \rfloor)
g(1)S(n)=i=1∑nh(i)−d=2∑ng(d)S(⌊dn⌋)
该式可以化简为:
S
(
n
)
=
1
−
∑
d
=
2
n
S
(
⌊
n
d
⌋
)
S(n)=1 - \sum_{d=2}^n S(\lfloor \frac nd \rfloor)
S(n)=1−d=2∑nS(⌊dn⌋)
例二:求
S
(
n
)
=
∑
i
=
1
n
φ
(
i
)
S(n)=\sum_{i=1}^n\varphi(i)
S(n)=∑i=1nφ(i)
我们知道:
φ
∗
I
=
i
d
\varphi *I=id
φ∗I=id
因此同样可以化简为:
S
(
n
)
=
∑
i
=
1
n
i
−
∑
d
=
2
n
S
(
⌊
n
d
⌋
)
S(n)=\sum_{i=1}^n i- \sum_{d=2}^n S(\lfloor \frac nd \rfloor)
S(n)=i=1∑ni−d=2∑nS(⌊dn⌋)
例三:求
S
(
n
)
=
∑
i
=
1
n
i
×
φ
(
i
)
S(n)=\sum_{i=1}^{n}i \times \varphi(i)
S(n)=∑i=1ni×φ(i)
(1)我们观察:
f
(
i
)
=
i
×
φ
(
i
)
f(i)=i \times \varphi(i)
f(i)=i×φ(i)
(2)然后考虑:
f
∗
g
f*g
f∗g的卷积形式:
h
=
f
∗
g
=
∑
d
∣
n
d
×
φ
(
d
)
g
(
n
d
)
h=f*g=\sum_{d|n}d\times \varphi(d)\ g(\frac nd)
h=f∗g=∑d∣nd×φ(d) g(dn)
(3)很明显,我们想要消去这个d,因此取g=id
化简:
h
=
∑
d
∣
n
d
×
φ
(
d
)
n
d
=
∑
d
∣
n
n
×
φ
(
d
)
=
n
2
h=\sum_{d|n}d\times \varphi(d)\ \frac nd=\sum_{d|n}n\times \varphi(d)=n^2
h=∑d∣nd×φ(d) dn=∑d∣nn×φ(d)=n2
(4)因此可以得到:
S
(
n
)
=
∑
i
=
1
n
i
2
−
∑
d
=
2
n
S
(
⌊
n
d
⌋
)
S(n)=\sum_{i=1}^n i^2- \sum_{d=2}^n S(\lfloor \frac nd \rfloor)
S(n)=i=1∑ni2−d=2∑nS(⌊dn⌋)
P4213 【模板】杜教筛(Sum)
题意:求欧拉函数和莫比乌斯函数的前缀和
分析:模板题。需要使用:快读、unordered_map记忆化、整除分块不能全用long long
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <unordered_map>
#include <cstring>
#include <string>
#include <cmath>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b) memset(a,b,sizeof(a))
#define mp make_pair
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define isZero(d) (abs(d) < 1e-8)
using namespace std;
const int maxn=6e6+10,INF=0x3f3f3f3f;
const int mod=1e9+7;
inline int read()
{
int X=0,w=1;
char c=getchar();
while (c<'0'||c>'9')
{
if (c=='-') w=-1;
c=getchar();
}
while (c>='0'&&c<='9')
X=X*10+c-'0',c=getchar();
return X*w;
}
int T,n;
const int N=6e6;
ll phi[maxn];
int visit[maxn],prime[maxn],mu[maxn],cnt;
inline void init()
{
mu[1]=1,phi[1]=1,cnt=0;
for(int i=2;i<=N;++i)
{
if(!visit[i])
prime[++cnt]=i,phi[i]=i-1,mu[i]=-1;
for(int j=1;j<=cnt&&i*prime[j]<=N;++j)
{
visit[i*prime[j]]=1;
if(i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*phi[prime[j]];
mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=N;++i)
phi[i]+=phi[i-1],mu[i]+=mu[i-1];
}
unordered_map<int,ll> mphi;
unordered_map<int,int> mmu;
inline ll calphi(int n)
{
if(n<=N)
return phi[n];
if(mphi[n])
return mphi[n];
int l=2,r;
ll ans=1ll*(1+n)*n/2;
while(l<=n)
{
r=n/(n/l);
ans-=1ll*(r-l+1)*calphi(n/l);
l=r+1;
}
return mphi[n]=ans;
}
inline int calmu(int n)
{
if(n<=N)
return mu[n];
if(mmu[n])
return mmu[n];
int l=2,r;
ll ans=1;
while(l<=n)
{
r=n/(n/l);
ans-=1ll*(r-l+1)*calmu(n/l);
l=r+1;
}
return mmu[n]=ans;
}
int main()
{
init();
T=read();
while(T--)
{
n=read();
printf("%lld %d\n",calphi(n),calmu(n));
}
return 0;
}