这篇学习笔记大部分内容参考自任之洲的论文《积性函数求和的几种方法》。
0 前置知识
1 一些定义
数论函数的定义
定义域为正整数域,陪域为负数域的函数被称为数论函数。
积性函数的定义
设 f 为一个数论函数,若对于每一对互质的 a,b 均满足 f(ab)=f(a)f(b),则 f 为积性函数。
特别的,设 g 为一个数论函数,若对于每一对 a,b 均班满足 g(ab)=g(a)g(b),则 g 为完全积性函数。
1.1 常见的积性函数
μ(n)=⎩⎪⎨⎪⎧1(−1)k0n=1n 为 k 个不同的质数之积其它情况
1.2 常见的完全积性函数
ϵ(n)={10n=1n>1
2 莫比乌斯反演
2.1 狄利克雷卷积
定义两个数论函数 f(n),g(n) 的狄利克雷卷积为:(记作 (f∗g)(n))
(f∗g)(n)=d∣n∑f(d)g(dn)
狄利克雷卷积满足以下运算定律:
-
交换律:f∗g=g∗f
-
结合律: (f∗g)∗h=f∗(g∗h)
-
分配律:f∗(g+h)=f∗g+f∗h
-
单位元:f∗ϵ=f
-
若 f,g 均为积性函数,则 f∗g 也为积性函数
2.2 莫比乌斯反演
定理 2.1. μ∗1=ϵ,即:(其中函数 1 为返回值恒为 1 的常数函数)
d∣n∑μ(d)=ϵ(n)
证明
设 n 有 k 个不同的质因子,则
d∣n∑μ(d)=i=0∑k(−1)iCki=i=0∑kCki(−1)i1k−i
根据二项式定理,可得:(这里规定 00=1)
i=0∑kCki(−1)i1k−i=(1−1)k=0k=ϵ(n)
所以莫比乌斯函数相当于是狄利克雷卷积下 1 的逆元。
定理 2.2.
设 f,g 是两个数论函数,且满足
f(n)=d∣n∑g(d)
则它们也满足
g(n)=d∣n∑μ(d)f(dn)
反之亦然,即
f=g∗1⇔g=μ∗f
证明
f=g∗1
两边同时卷上 μ,得:
f∗μ=g∗1∗μ
根据定理 2.1 得:
f∗μ=g
两侧都卷上 1,得:
f=g∗1
3 一些应用
P2257 YY的GCD
求
i=1∑nj=1∑m[gcd(i,j)∈Prime]
首先枚举质数 p,则原式可化为:
i=1∑nj=1∑m[gcd(i,j)=p]
即
i=1∑⌊pn⌋j=1∑⌊pm⌋[gcd(i,j)=1]
也就是
i=1∑⌊pn⌋j=1∑⌊pm⌋ϵ(gcd(i,j)=1)
通过定理 2.1 展开得
i=1∑⌊pn⌋j=1∑⌊pm⌋d∣gcd(i,j)∑μ(d)
变换求和顺序,得
d=1∑μ(d)i=1∑⌊pn⌋[d∣i]j=1∑⌊pm⌋[d∣j]
∵1∼⌊pn⌋ 中有 ⎣⎢⎢⎢⎢d⌊pn⌋⎦⎥⎥⎥⎥个 d 的倍数
∴ 得
d=1∑μ(d)⎣⎢⎢⎢⎢d⌊pn⌋⎦⎥⎥⎥⎥⎣⎢⎢⎢⎢d⌊pm⌋⎦⎥⎥⎥⎥
即
d=1∑min(⌊pn⌋,⌊pm⌋)μ(d)⌊pdn⌋⌊pdm⌋
显然可以使用数论分块求解。
但是这样还不够优,考虑继续化简:
设 T=pd,则原式变为
d=1∑min(⌊pn⌋,⌊pm⌋)μ(d)⌊Tn⌋⌊Tm⌋
也就是
T=1∑min(n,m)⌊Tn⌋⌊Tm⌋p∈Prime,p∣T∑μ(pT)
容易发现,最后那个求和可以预处理,最后套一下整除分块即可。
代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
const long long S=1e7+1;
int n,m;
bool nop[S+5];
int tot,prime[S+5];
int mu[S+5];
long long sum[S+5];
inline int read()
{
int s=0,w=1,ch=getchar();
while(ch<'0'||ch>'9') ch=='-'?w=-1,ch=getchar():ch=getchar();
while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
return s*w;
}
inline void writen(long long x)
{
if(x>9) writen(x/10);
putchar(x%10|48);
}
inline void init()
{
nop[1]=true;
mu[1]=1;
for(register int i=2;i<=S;++i)
{
if(!nop[i])
{
prime[++tot]=i;
mu[i]=-1;
}
for(register int j=1;j<=tot;++j)
{
if(i*prime[j]>S)
{
break;
}
nop[i*prime[j]]=true;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=tot;++i)
{
for(int j=1;j*prime[i]<=S;++j)
{
sum[j*prime[i]]+=mu[j];
}
}
for(int i=1;i<=S;++i)
{
sum[i]+=sum[i-1];
}
}
int main()
{
init();
int _=read();
while(_--)
{
n=read();
m=read();
if(n>m)
{
swap(n,m);
}
long long ans=0;
for(int l=1;l<=n;)
{
int r=min(n/(n/l),m/(m/l));
ans+=(sum[r]-sum[l-1])*(n/l)*(m/l);
l=r+1;
}
writen(ans);
printf("\n");
}
return 0;
}
P2522 [HAOI2011]Problem b
求
i=a∑bj=c∑d[gcd(i,j)=k]
根据容斥原理,这个柿子可以分成四块,每一块的形式都是
i=1∑nj=1∑m[gcd(i,j)=k]
即
d=1∑min(⌊kn⌋,⌊km⌋)μ(d)⌊kdn⌋⌊kdm⌋
可以使用数论分块求解。
4 练习题目
P1829 [国家集训队]Crash的数字表格 / JZPTAB
P3455 [POI2007]ZAP-Queries
P3327 [SDOI2015]约数个数和
P6810 「MCOI-02」Convex Hull 凸包