莫比乌斯反演,又称懵逼钨丝繁衍,顾名思义就是一种让蒟蒻懵逼得像一根钨丝繁衍一般智障的算法
蒟蒻做了一天的懵逼钨丝繁衍,感觉十分智障
莫比乌斯反演
概念
若有两个函数,
f
(
x
)
f(x)
f(x)和
F
(
x
)
F(x)
F(x),满足
F
(
n
)
=
∑
d
∣
n
f
(
d
)
F(n)=\sum_{d|n}f(d)
F(n)=d∣n∑f(d)
则有
f
(
x
)
=
∑
d
∣
n
μ
(
d
)
F
(
n
d
)
f(x)=\sum_{d|n}\mu(d)F(\frac n d)
f(x)=d∣n∑μ(d)F(dn)
其中
μ
\mu
μ为莫比乌斯函数
证明
目前有两种证法 (蒟蒻只知道两种):直接证和卷积
①直接证法:
∑ d ∣ n μ ( d ) F ( n d ) = ∑ d ∣ n μ ( d ) ∑ d ′ ∣ n d f ( d ′ ) = ∑ d ′ ∣ n f ( d ′ ) ∑ d ∣ n d ′ μ ( d ) = f ( n ) \sum_{d|n}\mu(d) F(\frac n d)=\sum_{d|n}\mu(d)\sum_{d'|\frac n d}f(d')=\sum_{d'|n}f(d')\sum_{d|\frac n {d'}}\mu(d)=f(n) d∣n∑μ(d)F(dn)=d∣n∑μ(d)d′∣dn∑f(d′)=d′∣n∑f(d′)d∣d′n∑μ(d)=f(n)
②卷积证法:
引自知乎
定义俩函数, F ( x ) F(x) F(x)和 f ( x ) f(x) f(x),设卷积运算 F ∗ f = ( F ∗ f ) ( n ) = ∑ i j = n F ( i ) f ( j ) F*f=(F*f)(n)=\sum_{ij=n}F(i)f(j) F∗f=(F∗f)(n)=ij=n∑F(i)f(j)
设卷积意义下的单位元 ι \iota ι使得 ι ∗ f = f \iota * f = f ι∗f=f
设乘法意义下的单位元 u u u使得 ( F f ) ( n ) = F ( n ) f ( n ) (Ff)(n)=F(n)f(n) (Ff)(n)=F(n)f(n),可得 u u u是 μ \mu μ在卷积意义下的逆元,即 u ∗ μ = ι u*\mu=\iota u∗μ=ι
莫比乌斯反演公式: F ( n ) = ∑ d ∣ n f ( n ) ⇔ f ( n ) = ∑ d ∣ n μ ( d ) F ( n d ) F(n)=\sum_{d|n}f(n) \Leftrightarrow f(n)=\sum_{d|n}\mu(d)F(\frac n d) F(n)=d∣n∑f(n)⇔f(n)=d∣n∑μ(d)F(dn)
变形: F = f ∗ u ⇔ f = F ∗ μ F=f*u \Leftrightarrow f=F*\mu F=f∗u⇔f=F∗μ
证明: F = f ∗ u F=f*u F=f∗u ⇔ F ∗ μ = f ∗ u ∗ μ \Leftrightarrow F*\mu=f*u*\mu ⇔F∗μ=f∗u∗μ ⇔ F ∗ μ = f ∗ ι \Leftrightarrow F*\mu=f*\iota ⇔F∗μ=f∗ι ⇔ F ∗ μ = f \Leftrightarrow F*\mu=f ⇔F∗μ=f
线性筛莫比乌斯函数
具体蒟蒻不会证,贴上代码吧
miu[1]=1;
for(rg int i=2;i<=5e4;++i){
if(!is[i])pri[++tot]=i,miu[i]=-1;
for(rg int j=1;j<=tot;++j){
rg int k=i*pri[j];if(k>5e4)break;
is[k]=1;
if(i%pri[j]==0){miu[k]=0;break;}
else miu[k]-=miu[i];
}
}
应用
GCD HDU-1695
题意
给定
a
a
a,
b
b
b,
c
c
c,求有序数对
(
x
,
y
)
(x,y)
(x,y)满足
x
∈
[
1
,
a
]
,
y
∈
[
1
,
b
]
,
g
c
d
(
x
,
y
)
=
c
x\in [1,a],y\in[1,b],gcd(x,y)=c
x∈[1,a],y∈[1,b],gcd(x,y)=c的个数
题解
首先简化问题,设答案为
a
n
s
(
a
,
b
,
c
)
ans(a,b,c)
ans(a,b,c),可证答案为
a
n
s
(
a
c
,
b
c
,
1
)
ans(\frac a c,\frac b c,1)
ans(ca,cb,1)
设
F
(
n
)
F(n)
F(n)表示
(
x
,
y
)
(x,y)
(x,y)满足
x
∈
[
1
,
a
]
,
y
∈
[
1
,
b
]
,
c
∣
g
c
d
(
x
,
y
)
x \in [1,a],y\in[1,b],c|gcd(x,y)
x∈[1,a],y∈[1,b],c∣gcd(x,y)的个数
设
f
(
n
)
f(n)
f(n)表示
(
x
,
y
)
(x,y)
(x,y)满足
x
∈
[
1
,
a
]
,
y
∈
[
1
,
b
]
,
g
c
d
(
x
,
y
)
=
c
x \in [1,a],y\in[1,b],gcd(x,y)=c
x∈[1,a],y∈[1,b],gcd(x,y)=c的个数
则可证
F
(
x
)
F(x)
F(x)与
f
(
x
)
f(x)
f(x)符合
F
(
n
)
=
∑
d
∣
n
f
(
n
)
F(n)=\sum_{d|n}f(n)
F(n)=∑d∣nf(n),最后答案为
f
(
1
)
f(1)
f(1)
可证
F
(
d
)
=
n
d
∗
m
d
F(d)=\frac n d *\frac m d
F(d)=dn∗dm
答案为
f
(
1
)
=
∑
d
m
i
n
(
a
,
b
)
μ
(
d
)
F
(
d
)
f(1)=\sum_{d}^{min(a,b)}\mu(d)F(d)
f(1)=∑dmin(a,b)μ(d)F(d)
代码
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
#define rg register
template <typename _Tp> inline void read(_Tp&x){
char c11=getchar();x=0;bool booo=0;
while(c11!='-'&&!isdigit(c11))c11=getchar();if(c11=='-'){c11=getchar();booo=1;}
while(isdigit(c11)){x=x*10+c11-'0';c11=getchar();}if(booo)x=-x;return ;
}
const int N=100500;
ll miu[N],is[N],pri[N],tot=0,ans1,ans2;
void pre_miu(){
miu[1]=1;
for(rg int i=2;i<=1e5;++i){
if(!is[i])pri[++tot]=i,miu[i]=-1;
for(rg int j=1;j<=tot;++j){
rg int k=pri[j]*i;if(k>1e5)break;
is[k]=1;
if(i%pri[j]==0){miu[k]=0;break;}
else miu[k]-=miu[i];
}
}
return ;
}
int main(){
rg int T,a,b,c;read(T);
pre_miu();
for(rg int cases=1;cases<=T;++cases){
ans1=ans2=0;
read(a);read(a);read(b);read(b);read(c);
if(!c){printf("Case %d: 0\n",cases);continue;}
a/=c,b/=c;
if(a>b)swap(a,b);
for(rg int i=1;i<=a;++i)
ans1+=(ll)miu[i]*(a/i)*(b/i),
ans2+=(ll)miu[i]*(a/i)*(a/i);
printf("Case %d: %lld\n",cases,ans1-(ans2>>1));
}
return 0;
}
[POI2007]ZAP-Queries
和楼上一样,不过数据大了一些,需要分块优化:由于有一段 n i \frac n i in是相同的,所以可以进行跳跃式加和,复杂度 O ( m i n ( n , m ) ) O(\sqrt {min(n,m)}) O(min(n,m))
代码
a/=c,b/=c,ans=0;
if(a>b)swap(a,b);
for(rg int i=1,j;i<=a;i=j+1){
j=min(a/(a/i),b/(b/i));
ans+=1ll*(sum[j]-sum[i-1])*(a/i)*(b/i);
}
[HAOI2011]Problem b
又和楼上差不多,只不过加了下限,用上容斥
后面两题和第一题代码类似,加以修改即可