反演的定义
设有数论函数
f
(
n
)
,
g
(
n
)
f(n),g(n)
f(n),g(n),其中
g
(
n
)
g(n)
g(n)已知
且
f
(
n
)
,
g
(
n
)
f(n),g(n)
f(n),g(n)满足关系
g
(
n
)
=
∑
i
=
0
n
a
n
,
i
f
(
i
)
g(n)=\sum_{i=0}^na_{n,i}f(i)
g(n)=∑i=0nan,if(i)
反演就是利用
g
(
n
)
g(n)
g(n)和已知关系推导出
f
(
n
)
f(n)
f(n)关于
g
(
i
)
g(i)
g(i)的表达
f
(
n
)
=
∑
i
=
0
n
b
n
,
i
g
(
i
)
f(n)=\sum_{i=0}^nb_{n,i}g(i)
f(n)=∑i=0nbn,ig(i)
莫比乌斯函数
了解莫比乌斯反演之前肯定要先了解莫比乌斯函数
设正整数
N
N
N按算术基本定理分解质因数为
N
=
∏
i
=
1
m
p
i
c
i
N=\prod_{i=1}^mp_i^{c_i}
N=∏i=1mpici
μ ( N ) = { 0 , ∃ i ∈ [ 1 , m ] , c i > 1 1 , m ≡ 0 ( m o d 2 ) , ∀ i ∈ [ 1 , m ] c i = 1 − 1 , m ≡ 1 ( m o d 2 ) , ∀ i ∈ [ 1 , m ] c i = 1 \mu(N)=\left\{\begin{aligned}0,\exists i\in[1,m],c_i>1 \\ 1,m\equiv 0(\mod 2),\forall i\in[1,m]c_i=1 \\ -1 ,m\equiv 1(\mod 2),\forall i\in[1,m]c_i=1\end{aligned}\right. μ(N)=⎩⎪⎨⎪⎧0,∃i∈[1,m],ci>11,m≡0(mod2),∀i∈[1,m]ci=1−1,m≡1(mod2),∀i∈[1,m]ci=1
即若
N
N
N含相同质因子,则
μ
(
N
)
=
0
\mu(N)=0
μ(N)=0
若
N
N
N所有质因子各不相等且质因子个数为偶数,则
μ
(
N
)
=
1
\mu(N)=1
μ(N)=1
若
N
N
N所有质因子各不相等且质因子个数为奇数,则
μ
(
N
)
=
−
1
\mu(N)=-1
μ(N)=−1
特别的 μ ( 1 ) = 1 \mu(1)=1 μ(1)=1
莫比乌斯函数的性质
- ∑ d ∣ n μ ( d ) = [ n = 1 ] \sum_{d|n}\mu(d)=[n=1] ∑d∣nμ(d)=[n=1]
这个性质是接下来证明的重要论据
- 莫比乌斯函数是积性函数
这个意味着莫比乌斯函数可以用埃式筛或线性筛求解
- 对任意正整数 N N N, ∑ d ∣ n μ ( d ) d = φ ( n ) n \sum_{d|n}\frac{\mu(d)}{d}=\frac{\varphi(n)}{n} ∑d∣ndμ(d)=nφ(n)
这个挺好玩的,但是没啥用
莫比乌斯反演
常见的莫比乌斯反演有两种形式
- g ( n ) = ∑ d ∣ n f ( d ) ⇐ ⇒ f ( n ) = ∑ d ∣ n μ ( d ) g ( n d ) g(n)=\sum_{d|n}f(d)\ \Leftarrow \Rightarrow \ f(n)=\sum_{d|n}\mu(d)g(\frac{n}{d}) g(n)=d∣n∑f(d) ⇐⇒ f(n)=d∣n∑μ(d)g(dn)
- g ( n ) = ∑ n ∣ d f ( d ) ⇐ ⇒ f ( n ) = ∑ n ∣ d μ ( d n ) g ( d ) g(n)=\sum_{n|d}f(d)\ \Leftarrow \Rightarrow \ f(n)=\sum_{n|d}\mu(\frac{d}{n})g(d) g(n)=n∣d∑f(d) ⇐⇒ f(n)=n∣d∑μ(nd)g(d)
形式一证明
f
(
n
)
=
∑
d
∣
n
μ
(
d
)
g
(
n
d
)
f(n)=\sum_{d|n}\mu(d)g(\frac{n}{d})
f(n)=d∣n∑μ(d)g(dn)
=
∑
d
∣
n
μ
(
d
)
∑
k
∣
n
d
f
(
k
)
=
∑
d
∣
n
∑
k
∣
n
d
μ
(
d
)
f
(
k
)
=\sum_{d|n}\mu(d)\sum_{k|\frac{n}{d}}f(k)=\sum_{d|n}\sum_{k|\frac{n}{d}}\mu(d)f(k)
=d∣n∑μ(d)k∣dn∑f(k)=d∣n∑k∣dn∑μ(d)f(k)
注意到
d
,
k
d,k
d,k满足
d
∣
n
,
k
∣
(
n
/
d
)
d|n,k|(n/d)
d∣n,k∣(n/d),所以容易得出
k
∣
n
,
d
∣
(
n
/
k
)
k|n,d|(n/k)
k∣n,d∣(n/k),继续变换
∑ d ∣ n ∑ k ∣ n d μ ( d ) f ( k ) = ∑ k ∣ n ∑ d ∣ n k f ( k ) μ ( d ) = ∑ k ∣ n f ( k ) ∑ d ∣ n k μ ( d ) \sum_{d|n}\sum_{k|\frac{n}{d}}\mu(d)f(k)=\sum_{k|n}\sum_{d|\frac{n}{k}}f(k)\mu(d)=\sum_{k|n}f(k)\sum_{d|\frac{n}{k}}\mu(d) d∣n∑k∣dn∑μ(d)f(k)=k∣n∑d∣kn∑f(k)μ(d)=k∣n∑f(k)d∣kn∑μ(d)
根据前文所述莫比乌斯函数性质一
有
∑
d
∣
n
k
μ
(
d
)
=
[
n
=
k
]
\sum_{d|\frac{n}{k}}\mu(d)=[n=k]
∑d∣knμ(d)=[n=k],带入后得
f
(
n
)
=
f
(
n
)
∗
1
f(n)=f(n)*1
f(n)=f(n)∗1成立
证毕
形式二证明
证明过程与前面证明类似
f
(
n
)
=
∑
k
=
1
+
∞
μ
(
k
)
F
(
n
k
)
f(n)=\sum_{k=1}^{+\infty}\mu(k)F(nk)
f(n)=k=1∑+∞μ(k)F(nk)
=
∑
k
=
1
+
∞
μ
(
k
)
∑
n
k
∣
t
f
(
t
)
=\sum_{k=1}^{+\infty}\mu(k)\sum_{nk|t}f(t)
=k=1∑+∞μ(k)nk∣t∑f(t)
=
∑
n
∣
t
f
(
t
)
∑
k
∣
t
n
μ
(
k
)
=\sum_{n|t}f(t)\sum_{k|\frac{t}{n}}μ(k)
=n∣t∑f(t)k∣nt∑μ(k)
同样带入性质一得证
莫比乌斯反演的应用
洛谷P3455 [POI2007]ZAP-Queries
对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d
1
≤
n
≤
50000
,
1
≤
d
≤
a
,
b
≤
50000
1≤n≤50 000,1≤d≤a,b≤50 000
1≤n≤50000,1≤d≤a,b≤50000
莫比乌斯反演的经典例题
设
f
(
k
)
f(k)
f(k)表示满足条件的
(
x
,
y
)
(x,y)
(x,y)数量,即
f
(
k
)
=
∑
i
=
1
a
∑
j
=
1
b
[
g
c
d
(
i
,
j
)
=
k
]
f(k)=\sum_{i=1}^a\sum_{j=1}^b[gcd(i,j)=k]
f(k)=∑i=1a∑j=1b[gcd(i,j)=k]
g
(
k
)
g(k)
g(k)表示满足
g
c
d
(
x
,
y
)
m
o
d
k
=
=
0
gcd(x,y)\mod k==0
gcd(x,y)modk==0得
(
x
,
y
)
(x,y)
(x,y)数量
(
x
≤
a
,
y
≤
b
)
(x\leq a,y\leq b)
(x≤a,y≤b)
那么有 g ( n ) = ⌊ a n ⌋ ⌊ b n ⌋ = ∑ n ∣ k f ( k ) g(n)=\lfloor\frac{a}{n}\rfloor\lfloor\frac{b}{n}\rfloor=\sum_{n|k}f(k) g(n)=⌊na⌋⌊nb⌋=n∣k∑f(k)
于是根据上述反演公式得 a n s = f ( d ) = ∑ d ∣ k μ ( ⌊ k d ⌋ ) g ( k ) ans=f(d)=\sum_{d|k}\mu(\lfloor\frac{k}{d}\rfloor)g(k) ans=f(d)=d∣k∑μ(⌊dk⌋)g(k)
令
t
=
k
/
d
t=k/d
t=k/d
∑
t
=
1
m
i
n
(
⌊
a
d
⌋
,
⌊
b
d
⌋
)
μ
(
t
)
⌊
a
t
d
⌋
⌊
b
t
d
⌋
\sum_{t=1}^{min(\lfloor\frac{a}{d}\rfloor,\lfloor\frac{b}{d}\rfloor)}\mu(t)\lfloor\frac{a}{td}\rfloor\lfloor\frac{b}{td}\rfloor
t=1∑min(⌊da⌋,⌊db⌋)μ(t)⌊tda⌋⌊tdb⌋
到这里已经可以
O
(
n
)
O(n)
O(n)处理每次询问,但由于多组询问复杂度还是不太乐观
对于
⌊
a
t
d
⌋
⌊
b
t
d
⌋
\lfloor\frac{a}{td}\rfloor\lfloor\frac{b}{td}\rfloor
⌊tda⌋⌊tdb⌋这一部分用整除分块处理,处理一次询问的时间复杂度为
O
(
n
)
O(\sqrt n)
O(n)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long lt;
lt read()
{
lt f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int maxn=50010;
int T;
int miu[maxn],vis[maxn];
int prim[maxn],cnt;
lt sum[maxn];
void Miu(int n)
{
miu[1]=1;
for(int i=2;i<=n;++i)
{
if(!vis[i]){ miu[i]=-1; prim[++cnt]=i;}
for(int j=1;j<=cnt;++j)
{
if(prim[j]*i>n) break;
vis[prim[j]*i]=1;
if(i%prim[j]==0) break;
else miu[i*prim[j]]=-miu[i];
}
}
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+miu[i];
}
int main()
{
T=read(); Miu(maxn-10);
while(T--)
{
lt a=read(),b=read(),d=read();
lt ans=0,lim=min(a/d,b/d);
int ad=a/d,bd=b/d;
for(int ll=1,rr;ll<=lim;ll=rr+1)
{
rr=min(ad/(ad/ll),bd/(bd/ll));
ans+=(a/(ll*d))*(b/(ll*d))*(sum[rr]-sum[ll-1]);
}
printf("%lld\n",ans);
}
return 0;
}
换个角度看反演
其实大多时候解反演题并不一定要设出
f
(
n
)
,
g
(
n
)
f(n),g(n)
f(n),g(n)
把莫比乌斯反演公式的推导过程铺开
我们会发现其实就是在想办法构造
∑
d
∣
n
μ
(
d
)
=
[
n
=
=
1
]
\sum_{d|n}\mu(d)=[n==1]
∑d∣nμ(d)=[n==1]
那上面这题为例换个方法反演,首先
a
n
s
=
∑
i
=
1
a
∑
j
=
1
b
[
g
c
d
(
i
,
j
)
=
d
]
ans=\sum_{i=1}^a\sum_{j=1}^b[gcd(i,j)=d]
ans=∑i=1a∑j=1b[gcd(i,j)=d]
若
g
c
d
(
x
,
y
)
=
1
gcd(x,y)=1
gcd(x,y)=1,则有
g
c
d
(
x
∗
d
,
y
∗
d
)
=
d
gcd(x*d,y*d)=d
gcd(x∗d,y∗d)=d,于是上述式子变形得
∑ x = 1 ⌊ a d ⌋ ∑ y = 1 ⌊ b d ⌋ [ g c d ( x , y ) = 1 ] \sum_{x=1}^{\lfloor\frac{a}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{b}{d}\rfloor}[gcd(x,y)=1] x=1∑⌊da⌋y=1∑⌊db⌋[gcd(x,y)=1]
现在我们惊喜的发现 [ g c d ( x , y ) = 1 ] [gcd(x,y)=1] [gcd(x,y)=1]可以用莫比乌斯函数性质一做个替换
∑ x = 1 ⌊ a d ⌋ ∑ y = 1 ⌊ b d ⌋ ∑ t ∣ g c d ( x , y ) μ ( t ) \sum_{x=1}^{\lfloor\frac{a}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{b}{d}\rfloor}\sum_{t|gcd(x,y)}\mu(t) x=1∑⌊da⌋y=1∑⌊db⌋t∣gcd(x,y)∑μ(t)
把枚举约数提前
∑ t = 1 m i n ( ⌊ a d ⌋ , ⌊ b d ⌋ ) ∑ x = 1 ⌊ a d ⌋ ∑ y = 1 ⌊ b d ⌋ μ ( t ) [ t ∣ g c d ( x , y ) ] \sum_{t=1}^{min(\lfloor\frac{a}{d}\rfloor,\lfloor\frac{b}{d}\rfloor)}\sum_{x=1}^{\lfloor\frac{a}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{b}{d}\rfloor}\mu(t)[t|gcd(x,y)] t=1∑min(⌊da⌋,⌊db⌋)x=1∑⌊da⌋y=1∑⌊db⌋μ(t)[t∣gcd(x,y)]
若
[
t
∣
g
c
d
(
x
,
y
)
]
=
1
[t|gcd(x,y)]=1
[t∣gcd(x,y)]=1成立,则
t
∣
x
,
t
∣
y
t|x,t|y
t∣x,t∣y,所以把枚举
x
,
y
x,y
x,y变成枚举
t
t
t的倍数
最后把
μ
(
t
)
\mu(t)
μ(t)提前
∑ t = 1 m i n ( ⌊ a d ⌋ , ⌊ b d ⌋ ) μ ( t ) ∑ t 1 = 1 ⌊ a d t ⌋ ∑ t 2 = 1 ⌊ b d t ⌋ 1 = ∑ t = 1 m i n ( ⌊ a d ⌋ , ⌊ b d ⌋ ) μ ( t ) ⌊ a t d ⌋ ⌊ b t d ⌋ \sum_{t=1}^{min(\lfloor\frac{a}{d}\rfloor,\lfloor\frac{b}{d}\rfloor)}\mu(t)\sum_{t_1=1}^{\lfloor\frac{a}{dt}\rfloor}\sum_{t_2=1}^{\lfloor\frac{b}{dt}\rfloor}1=\sum_{t=1}^{min(\lfloor\frac{a}{d}\rfloor,\lfloor\frac{b}{d}\rfloor)}\mu(t)\lfloor\frac{a}{td}\rfloor\lfloor\frac{b}{td}\rfloor t=1∑min(⌊da⌋,⌊db⌋)μ(t)t1=1∑⌊dta⌋t2=1∑⌊dtb⌋1=t=1∑min(⌊da⌋,⌊db⌋)μ(t)⌊tda⌋⌊tdb⌋
竟然得到了完全一样的答案!!
所以这说明不是遇上反演的题就一定要凑出
f
,
g
f,g
f,g和公式所述的关系
而是应该思考如何将表达式构造出能利用
∑
d
∣
n
μ
(
d
)
=
[
n
=
=
1
]
\sum_{d|n}\mu(d)=[n==1]
∑d∣nμ(d)=[n==1]的形式
继续懵逼反演的应用
BZOJ2301 [HAOI2011]Problem b
对于给定的整数a,b,c,d,k,有多少正整数对x,y,满足a<=x<=b,c<=y<=d,并且gcd(x,y)=k
1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000
和上一题大同小异,加一个容斥即可
如果被卡常的话可以考虑把一些没必要开long long的变量换成int
以及
a
/
k
,
b
/
k
a/k,b/k
a/k,b/k这种重复计算的可以先处理,可以快很多
lt query(int a,int b)
{
lt res=0;
int ak=a/k,bk=b/k,lim=min(a/k,b/k);
for(int ll=1,rr;ll<=lim;ll=rr+1)
{
rr=min(ak/(ak/ll),bk/(bk/ll));
res+=(lt)(ak/ll)*(bk/ll)*(sum[rr]-sum[ll-1]);
}
return res;
}
lt ans=query(b,d)-query(b,c-1)-query(a-1,d)+query(a-1,c-1);
HDU - 1695 GCD
对于给定的整数a,b,c,d,k,有多少正整数对x,y,满足1<=x<=b,1<=y<=d,并且gcd(x,y)=k
(x=i,y=j)与(x=j,y=i)等价
T<=3000,0 < a <= b <= 100,000, 0 < c <= d <= 100,000, 0 <= k <= 100,000
和第一题区别在于去重,由于只有
x
<
=
b
,
y
<
=
b
(
b
<
d
)
x<=b,y<=b(b<d)
x<=b,y<=b(b<d)这部分会有重复,所以减去这部分总数的一半
以及注意特判k==0的情况
if(b>d) swap(b,d);
lt ans1=query(b,d,k),ans2=query(b,b,k);
printf("Case %d: %lld\n",cs,ans1-ans2/2);
洛谷P2257 YY的GCD
给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对
T = 10000,N, M <= 10000000
首先这题
f
(
k
)
,
g
(
k
)
f(k),g(k)
f(k),g(k)定义依然同上 (一般看到gcd的题都会想到这么设函数)
回顾上面反演后的式子
f
(
d
)
=
∑
d
∣
k
μ
(
⌊
k
d
⌋
)
g
(
k
)
=
∑
t
=
1
m
i
n
(
⌊
N
d
⌋
,
⌊
M
d
⌋
)
μ
(
t
)
⌊
N
t
d
⌋
⌊
M
t
d
⌋
f(d)=\sum_{d|k}\mu(\lfloor\frac{k}{d}\rfloor)g(k)=\sum_{t=1}^{min(\lfloor\frac{N}{d}\rfloor,\lfloor\frac{M}{d}\rfloor)}\mu(t)\lfloor\frac{N}{td}\rfloor\lfloor\frac{M}{td}\rfloor
f(d)=d∣k∑μ(⌊dk⌋)g(k)=t=1∑min(⌊dN⌋,⌊dM⌋)μ(t)⌊tdN⌋⌊tdM⌋
现在考虑将这个式子应用到此题
a
n
s
=
∑
p
∈
p
r
i
m
e
f
(
p
)
=
∑
p
∈
p
r
i
m
e
∑
p
∣
k
μ
(
⌊
k
p
⌋
)
g
(
k
)
=
∑
p
∈
p
r
i
m
e
∑
t
=
1
m
i
n
(
⌊
N
p
⌋
,
⌊
M
p
⌋
)
μ
(
t
)
⌊
N
t
p
⌋
⌊
M
t
p
⌋
ans=\sum_{p\in prime}f(p)=\sum_{p\in prime}\sum_{p|k}\mu(\lfloor\frac{k}{p}\rfloor)g(k)=\sum_{p\in prime}\sum_{t=1}^{min(\lfloor\frac{N}{p}\rfloor,\lfloor\frac{M}{p}\rfloor)}\mu(t)\lfloor\frac{N}{tp}\rfloor\lfloor\frac{M}{tp}\rfloor
ans=p∈prime∑f(p)=p∈prime∑p∣k∑μ(⌊pk⌋)g(k)=p∈prime∑t=1∑min(⌊pN⌋,⌊pM⌋)μ(t)⌊tpN⌋⌊tpM⌋
令 T = t p T=tp T=tp,继续变形得
∑
T
=
1
m
i
n
(
N
,
M
)
∑
p
∣
T
,
p
∈
p
r
i
m
e
μ
(
T
p
)
⌊
N
T
⌋
⌊
M
T
⌋
=
∑
T
=
1
m
i
n
(
N
,
M
)
⌊
N
T
⌋
⌊
M
T
⌋
∑
p
∣
T
,
p
∈
p
r
i
m
e
μ
(
T
p
)
\sum_{T=1}^{min(N,M)}\sum_{p|T,p\in prime}\mu(\frac{T}{p})\lfloor\frac{N}{T}\rfloor\lfloor\frac{M}{T}\rfloor=\sum_{T=1}^{min(N,M)}\lfloor\frac{N}{T}\rfloor\lfloor\frac{M}{T}\rfloor\sum_{p|T,p\in prime}\mu(\frac{T}{p})
T=1∑min(N,M)p∣T,p∈prime∑μ(pT)⌊TN⌋⌊TM⌋=T=1∑min(N,M)⌊TN⌋⌊TM⌋p∣T,p∈prime∑μ(pT)
于是后面那一坨可以预处理前缀和,每次询问用整除分块处理即可
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long lt;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int maxn=10000010;
int T;
int miu[maxn],vis[maxn];
int prim[maxn],cnt;
lt sum[maxn];
void Miu(int n)
{
miu[1]=1;
for(int i=2;i<=n;++i)
{
if(!vis[i]){ miu[i]=-1; prim[++cnt]=i;}
for(int j=1;j<=cnt;++j)
{
if(prim[j]*i>n) break;
vis[prim[j]*i]=1;
if(i%prim[j]==0) break;
else miu[i*prim[j]]=-miu[i];
}
}
for(int i=1;i<=cnt;++i)
for(int j=1;prim[i]*j<=n;++j) sum[prim[i]*j]+=miu[j];
for(int i=1;i<=n;++i) sum[i]=sum[i-1]+sum[i];
}
lt query(int n,int m)
{
lt res=0; int lim=min(n,m);
for(int ll=1,rr;ll<=lim;ll=rr+1)
{
rr=min(n/(n/ll),m/(m/ll));
res+=(lt)(n/ll)*(m/ll)*(sum[rr]-sum[ll-1]);
}
return res;
}
int main()
{
T=read(); Miu(maxn-5);
while(T--)
{
int n=read(),m=read();
printf("%lld\n",query(n,m));
}
return 0;
}
其他懵逼反演应用推导比较长,戳下面链接看噢
BZOJ2154 || 洛谷P1829 [国家集训队]Crash的数字表格 题解
BZOJ3529 || 洛谷P3312 [SDOI2014]数表 题解
BZOJ3994 || P3327 [SDOI2015]约数个数和 题解