莫比乌斯反演
莫比乌斯反演
应该比较清晰易懂吧(雾
莫比乌斯函数
定义
x
=
p
1
α
1
p
2
α
2
…
p
k
α
k
,
其
中
p
i
是
质
数
,
α
i
是
正
整
数
x=p_1^{\alpha_1}p_2^{\alpha_2}\dots p_k^{\alpha_k} ,其中p_i是质数,\alpha_i是正整数
x=p1α1p2α2…pkαk,其中pi是质数,αi是正整数
μ
(
x
)
=
{
c
a
s
e
1
:
存
在
α
i
≥
2
,
此
时
μ
(
x
)
=
0.
c
a
s
e
2
:
所
有
的
α
i
=
1
,
此
时
μ
(
x
)
=
(
−
1
)
k
.
例
:
μ
(
6
)
=
1
,
μ
(
7
)
=
−
1
,
μ
(
8
)
=
0.
\mu(x)=\begin{cases} case1: 存在\alpha_i \geq2 ,此时\mu(x)=0.\\ case2: 所有的\alpha_i=1,此时\mu(x)=(-1)^k.\\ \end{cases} 例:\mu(6)=1,\mu(7)=-1,\mu(8)=0.
μ(x)={case1:存在αi≥2,此时μ(x)=0.case2:所有的αi=1,此时μ(x)=(−1)k.例:μ(6)=1,μ(7)=−1,μ(8)=0.
s(n)
s ( n ) = ∑ d ∣ n μ ( d ) s(n)=\sum_{d|n}\mu(d) s(n)=∑d∣nμ(d)
即n的所有约数的莫比乌斯函数值之和
有:
s
(
n
)
=
{
1
,
n
=
1.
0
,
n
>
1.
s(n)=\begin{cases} 1,n=1.\\ 0,n>1.\\ \end{cases}
s(n)={1,n=1.0,n>1.
反演
若 F ( n ) = ∑ d ∣ n f ( d ) , 则 f ( n ) = ∑ d ∣ n μ ( d ) F ( n d ) F(n)=\sum_{d|n}f(d),则f(n)=\sum_{d|n}\mu(d)F(\frac{n}{d}) F(n)=∑d∣nf(d),则f(n)=∑d∣nμ(d)F(dn)
简而言之,就是如果我们已知F函数,我们通过套公式可以求出f
因此在某些情况下F函数很好求,我们就可以通过反演求出f
后面的例题就是要靠我们找出哪个是F(n),哪个是f(n),然后把难求的转化成好求的
推导:
∑ d ∣ n μ ( d ) F ( n d ) = ∑ d ∣ n μ ( d ) ∑ i ∣ n d f ( i ) = ∑ i ∣ n f ( i ) ∑ d ∣ n i μ ( d ) \sum_{d|n}\mu(d)F(\frac{n}{d})=\sum_{d|n}\mu(d)\sum_{i|\frac{n}{d}}f(i)=\sum_{i|n}f(i)\sum_{d|\frac{n}{i}}\mu(d) ∑d∣nμ(d)F(dn)=∑d∣nμ(d)∑i∣dnf(i)=∑i∣nf(i)∑d∣inμ(d)
其中: ∑ d ∣ n i μ ( d ) = s ( n i ) \sum_{d|\frac{n}{i}}\mu(d)=s(\frac{n}{i}) ∑d∣inμ(d)=s(in)
n = i 时 , 原 式 = f ( n ) , i < n 时 原 式 = 0 n=i时,原式=f(n),i<n时原式=0 n=i时,原式=f(n),i<n时原式=0
一般情况下,我们经常用这个式子(枚举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{d}{n})F(d) f(n)=∑n∣dμ(nd)F(d)
例题
显然容斥
S = S b , d − S a − 1 , d − S b , c − 1 + S a − 1 , c − 1 S=S_{b,d}-S_{a-1,d}-S_{b,c-1}+S_{a-1,c-1} S=Sb,d−Sa−1,d−Sb,c−1+Sa−1,c−1
接着我们考虑怎么定义 F ( n ) , f ( n ) F(n),f(n) F(n),f(n),使得 F ( n ) F(n) F(n)尽量好求
在本题中,我们定义 F ( n ) = ∑ x = 1 a ∑ y = 1 b [ n ∣ g c d ( x , y ) ] F(n)=\sum^a_{x=1}\sum^b_{y=1}[n|gcd(x,y)] F(n)=∑x=1a∑y=1b[n∣gcd(x,y)]
这里的
[
…
]
[\dots]
[…]表示一个条件,满足是1
,不满足是0
翻译一下:
F
(
n
)
F(n)
F(n)表示在
a
,
b
a,b
a,b范围内的点对
(
x
,
y
)
(x,y)
(x,y)的
g
c
d
gcd
gcd是n
的倍数的点的数量
我们定义 f ( n ) = ∑ x = 1 a ∑ y = 1 b [ n = = g c d ( x , y ) ] f(n)=\sum^a_{x=1}\sum^b_{y=1}[n==gcd(x,y)] f(n)=∑x=1a∑y=1b[n==gcd(x,y)]
gcd
刚好等于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{d}{n})F(d) f(n)=∑n∣dμ(nd)F(d)
那么我们怎么求出
F
(
d
)
F(d)
F(d)呢?(d和n这个字母先混用,d好像有歧义,不过问题不大)
由 d ∣ g c d ( x , y ) d|gcd(x,y) d∣gcd(x,y)可知 d ∣ x d|x d∣x且 d ∣ y d|y d∣y
在a,b
范围内,我们有
⌊
a
d
⌋
\lfloor\frac{a}{d}\rfloor
⌊da⌋个横坐标是d
的倍数,
⌊
b
d
⌋
\lfloor\frac{b}{d}\rfloor
⌊db⌋个纵坐标是d
的倍数
因此 F ( d ) = ⌊ a d ⌋ × ⌊ b d ⌋ F(d)=\lfloor\frac{a}{d}\rfloor\times\lfloor\frac{b}{d}\rfloor F(d)=⌊da⌋×⌊db⌋
即 f ( n ) = ∑ n ∣ d μ ( d n ) ⌊ a d ⌋ ⌊ b d ⌋ f(n)=\sum_{n|d} \mu(\frac{d}{n})\lfloor\frac{a}{d}\rfloor\lfloor\frac{b}{d}\rfloor f(n)=∑n∣dμ(nd)⌊da⌋⌊db⌋
我们用d'
表示
d
n
\frac{d}{n}
nd,那么d'
的取值就是1,2,3,4...
那么 f ( n ) = ∑ d ′ μ ( d ′ ) ⌊ a d ′ n ⌋ ⌊ b d ′ n ⌋ f(n)=\sum_{d'}\mu(d')\lfloor\frac{a}{d'n}\rfloor\lfloor\frac{b}{d'n}\rfloor f(n)=∑d′μ(d′)⌊d′na⌋⌊d′nb⌋
再用a',b'
表示
a
n
,
b
n
\frac{a}{n},\frac{b}{n}
na,nb
整理得: f ( n ) = ∑ d ′ μ ( d ′ ) ⌊ a ′ d ′ ⌋ ⌊ b ′ d ′ ⌋ f(n)=\sum_{d'}\mu(d')\lfloor\frac{a'}{d'}\rfloor\lfloor\frac{b'}{d'}\rfloor f(n)=∑d′μ(d′)⌊d′a′⌋⌊d′b′⌋
不难发现分子;是定值,而分母的取值是1,2,3,4...
,因此分数下取整有
2
n
2\sqrt{n}
2n种取值,证明就不写了
关于整数分块:
虽然 ⌊ k x ⌋ \lfloor\frac{k}{x}\rfloor ⌊xk⌋,有k个取值,但共有 2 n 2\sqrt{n} 2n种取值
可以发现k
取不同的值时分数值为相通,连续的一段
对于一个x
我么如何求出是的分数值与该取值相等的最大取值呢?(问号所指处)
一般我们把这个取值叫 g ( x ) g(x) g(x)
g
(
x
)
=
⌊
k
⌊
k
x
⌋
⌋
g(x)=\lfloor\frac{k}{\lfloor\frac{k}{x}\rfloor}\rfloor
g(x)=⌊⌊xk⌋k⌋,就是k/(k/x)
回到本题中,我们把a',b'
分块,其中蓝色的重合部分,分数取值是相同的
其中c
可以带入算,
μ
\mu
μ可以预处理前缀和计算
然后每一段进行这种计算,就OK
了
Code:
/*************************************************************************
> File Name: [HAOI2011]Problemb.cpp
> Author: typedef
> Mail: 1815979752@qq.com
> Created Time: 2021/2/20 7:25:55
************************************************************************/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=50010;
int primes[N],cnt,mu[N],sum[N];
bool st[N];
void init(){
mu[1]=1;
for(int i=2;i<N;i++){
if(!st[i]) primes[cnt++]=i,mu[i]=-1;
for(int j=0;primes[j]*i<N;j++){
st[primes[j]*i]=1;
if(i%primes[j]==0) break;
mu[primes[j]*i]=-mu[i];
}
}
for(int i=1;i<N;i++) sum[i]=sum[i-1]+mu[i];
return;
}
int g(int k,int x){
return k/(k/x);
}
ll f(int a,int b,int k){
a=a/k,b=b/k;
ll res=0;
int n=min(a,b);
for(int l=1,r;l<=n;l=r+1){
r=min(n,min(g(a,l),g(b,l)));
res+=(ll)(sum[r]-sum[l-1])*(a/l)*(b/l);
}
return res;
}
int main(){
init();
int T;
scanf("%d",&T);
while(T--){
int a,b,c,d,k;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
printf("%lld\n",f(b,d,k)-f(a-1,d,k)-f(b,c-1,k)+f(a-1,c-1,k));
}
system("pause");
return 0;
}
题目描述:设
d
(
x
)
d(x)
d(x)为x
的的约数个数,给定N,M
求
∑ i = 1 N ∑ j = 1 M d ( i j ) \sum_{i=1}^{N}\sum_{j=1}^{M}d(ij) ∑i=1N∑j=1Md(ij)
转化一下:
d ( i j ) = ∑ x ∣ i ∑ y ∣ j [ g c d ( x , y ) = = 1 ] d(ij)=\sum_{x|i}\sum_{y|j}[gcd(x,y)==1] d(ij)=∑x∣i∑y∣j[gcd(x,y)==1]
原式= ∑ i = 1 N ∑ j = 1 M ∑ x ∣ i ∑ y ∣ j [ g c d ( x , y ) = = 1 ] \sum_{i=1}^{N}\sum_{j=1}^{M}\sum_{x|i}\sum_{y|j}[gcd(x,y)==1] ∑i=1N∑j=1M∑x∣i∑y∣j[gcd(x,y)==1]
设 F ( n ) = ∑ i = 1 N ∑ j = 1 M ∑ x ∣ i ∑ y ∣ j [ n ∣ g c d ( x , y ) ] F(n)=\sum_{i=1}^{N}\sum_{j=1}^{M}\sum_{x|i}\sum_{y|j}[n|gcd(x,y)] F(n)=∑i=1N∑j=1M∑x∣i∑y∣j[n∣gcd(x,y)]
设 f ( n ) = ∑ i = 1 N ∑ j = 1 M ∑ x ∣ i ∑ y ∣ j [ g c d ( x , y ) = = n ] f(n)=\sum_{i=1}^{N}\sum_{j=1}^{M}\sum_{x|i}\sum_{y|j}[gcd(x,y)==n] f(n)=∑i=1N∑j=1M∑x∣i∑y∣j[gcd(x,y)==n]
由 F ( n ) = ∑ n ∣ d f ( n ) F(n)=\sum_{n|d}f(n) F(n)=∑n∣df(n),得 f ( n ) = ∑ n ∣ d μ ( d n ) F ( d ) f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d) f(n)=∑n∣dμ(nd)F(d)
f ( 1 ) = ∑ d = 1 N μ ( d ) F ( d ) f(1)=\sum_{d=1}^{N}\mu(d)F(d) f(1)=∑d=1Nμ(d)F(d)即为所求
那么怎么求 F ( d ) F(d) F(d)呢?
交换一下 ∑ \sum ∑得
F ( n ) = ∑ x = 1 N ∑ y = 1 M ⌊ N x ⌋ ⌊ M y ⌋ [ n ∣ g c d ( x , y ) ] F(n)=\sum_{x=1}^{N}\sum_{y=1}^{M}\lfloor\frac{N}{x}\rfloor\lfloor\frac{M}{y}\rfloor[n|gcd(x,y)] F(n)=∑x=1N∑y=1M⌊xN⌋⌊yM⌋[n∣gcd(x,y)]
令x'
表示
x
n
\frac{x}{n}
nx,y'
表示
y
n
\frac{y}{n}
ny
带入得 F ( n ) = ∑ x ′ = 1 N n ∑ y ′ = 1 M n ⌊ N n x ′ ⌋ ⌊ M n y ′ ⌋ F(n)=\sum_{x'=1}^{\frac{N}{n}}\sum_{y'=1}^{\frac{M}{n}}\lfloor\frac{N}{nx'}\rfloor\lfloor\frac{M}{ny'}\rfloor F(n)=∑x′=1nN∑y′=1nM⌊nx′N⌋⌊ny′M⌋
再令N',M'
表示
N
n
\frac{N}{n}
nN和
M
n
\frac{M}{n}
nM
F ( n ) = ∑ x ′ = 1 N ′ ∑ y ′ = 1 M ′ ⌊ N ′ x ′ ⌋ ⌊ M ′ y ′ ⌋ = ( ∑ x ′ = 1 N ′ ⌊ N ′ x ′ ⌋ ) ( ∑ y ′ = 1 M ′ ⌊ M ′ y ′ ⌋ ) F(n)=\sum_{x'=1}^{N'}\sum_{y'=1}^{M'}\lfloor\frac{N'}{x'}\rfloor\lfloor\frac{M'}{y'}\rfloor=(\sum_{x'=1}^{N'}\lfloor\frac{N'}{x'}\rfloor)(\sum_{y'=1}^{M'}\lfloor\frac{M'}{y'}\rfloor) F(n)=∑x′=1N′∑y′=1M′⌊x′N′⌋⌊y′M′⌋=(∑x′=1N′⌊x′N′⌋)(∑y′=1M′⌊y′M′⌋)
括号内两式形式一样,均为: h ( k ) = ∑ i = 1 k ⌊ k i ⌋ h(k)=\sum_{i=1}^{k}\lfloor\frac{k}{i}\rfloor h(k)=∑i=1k⌊ik⌋
因此 F ( n ) = h ( N ′ ) h ( M ′ ) F(n)=h(N')h(M') F(n)=h(N′)h(M′)
f ( 1 ) = ∑ d = 1 N μ ( d ) h ( N d ) h ( M d ) f(1)=\sum_{d=1}^{N}\mu(d)h(\frac{N}{d})h(\frac{M}{d}) f(1)=∑d=1Nμ(d)h(dN)h(dM)
我么可以先预处理出 h ( x ) h(x) h(x),使用整数分块,求出段的端点和段的值,从而求出和
回到 f ( 1 ) f(1) f(1)中,我们需要再套一次整数分块,就能够求出结果
Code
/*************************************************************************
> File Name: [SDOI2015]约数个数.cpp
> Author: typedef
> Mail: 1815979752@qq.com
> Created Time: 2021/2/20 11:21:29
************************************************************************/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=50010;
int primes[N],cnt,mu[N],sum[N],h[N];
bool st[N];
int g(int k,int x){
return k/(k/x);
}
void init(){
mu[1]=1;
for(int i=2;i<N;i++){
if(!st[i]) primes[cnt++]=i,mu[i]=-1;
for(int j=0;primes[j]*i<N;j++){
st[primes[j]*i]=1;
if(i%primes[j]==0) break;
mu[i*primes[j]]=-mu[i];
}
}
for(int i=1;i<N;i++) sum[i]=sum[i-1]+mu[i];
for(int i=1;i<N;i++){
for(int l=1,r;l<=i;l=r+1){
r=min(i,g(i,l));
h[i]+=(r-l+1)*(i/l);
}
}
return;
}
int main(){
init();
int T;
scanf("%d",&T);
while(T--){
int n,m;
scanf("%d%d",&n,&m);
ll res=0;
int k=min(m,n);
for(int l=1,r;l<=k;l=r+1){
r=min(k,min(g(n,l),g(m,l)));
res+=(ll)(sum[r]-sum[l-1])*h[n/l]*h[m/l];
}
printf("%lld\n",res);
}
system("pause");
return 0;
}