关于莫比乌斯反演

狄利克雷卷积与数论函数:

狄利克雷卷积写作:

\[f(x)*g(x)=(f*g)(x) \]

定义:

\[(f*g)(x)=\sum_{d|n}^nf(d)*g(n/d) \]

也可以写作:

\[(f*g)(x)=\sum_{x*y=n}^nf(x)*g(y) \]

狄利克雷卷积满足交换律与结合律:

\[\begin{cases} (f*g)(n)=\sum_{x*y=n}^n\limits f(x)*g(y)=\sum_{x*y=n}^n\limits g(x)*f(y)=(g*f)(n)\\ \\ ((f*g)*h)(n)=\sum_{x*y*z=n}^n\limits f(x)*g(y)*h(z)=(f*(g*h))(n)\\ \end{cases} \]

狄利克雷卷积是一个对称的结构

一些简单的数论函数:

定义:积性函数:

对于一个函数 \(F\) , 如果 \(gcd(a,b)=1\) 时有\(F(ab)=F(a)F(b)\),则该函数是积性函数。

定义:完全积性函数:

对于任意的整数 \(a\) 和 \(b\) 有 \(F(ab)=F(a)F(b)\)

很明显,完全积性函数∈积性函数。

一些常见的积性函数:

恒等函数,无论 \(n\) 是啥,它永远等于1:

\[I(n)=1 \]

元函数,当 \(n=1\) 时,函数值为 \(1\),否则为 \(0\):

\[e(n)=[n==1] \]

单位函数:

\[id(n)=n \]

幂函数,单位函数是它的特殊情况:

\[id^k(n)=n^k \]

欧拉函数,小于n的整数中,与n互质的数的个数:

\[\varphi(n)=\sum_{i=1}^{n-1}[gcd(i,n)==1] \]

以及下文要用到的莫比乌斯函数 \(\mu(n)\)

积性函数的一些性质:

\[\begin{cases} F(1)=F(1)F(1)→ F(1)=1\\ \\ F(x)=F(p_1^{k1})F(p_2^{k2})...F(p_m^{km})\\ \end{cases}\]


积性函数的逆也是积性函数:

首先,定义函数在狄利克雷卷积意义下的逆:

考虑:

\[(F*e)(n)=\sum_{d|n}^n[n/d==1]*F(d) \]

即:

\[(F*e)(n)=\sum_{d|n}^n[d==n]*F(d) \]

即:

\[F*e=F \]

那么,如果 \(G*F=e\) ,我们就说 \(F\) 与 \(G\) 互逆

\[G*F=e ⇔ G=F^{-1} \]

下证:

\[\begin{cases} F(ab)=F(a)F(b)\\ \\ gcd(a,b)==1\\ \end{cases} → F^{-1}(ab)=F^{-1}(a)F^{-1}(b)\]

因为:

\[e=\sum_{d|n}^nF(d)F^{-1}(n/d) \]

考虑归纳证明:

当 \(a=1\) 或 \(b=1\) 时:

若 \(a,b\) 均等于 \(1\) ,\(e(1)=F(1)*F^{-1}(1)=1\)

而 \(F(1)=1\) ,因此 \(F^{-1}(1)=1\)

当 \(a,b>1\) 时:

设,对于 \(\forall a'<a,b'<b\),都有 \(F^{-1}(a'b')=F^{-1}(a')F^{-1}(b')\)

下证 \(F^{-1}(ab)=F^{-1}(a)F^{-1}(b)\)

显然,有:

\[\sum_{d|n,d!=1}^nF(d)F^{-1}(n/d)+F(1)F^{-1}(n)=\sum_{d|n}^nF(d)F^{-1}(n/d) \]

即:

\[\sum_{d|n}^nF(d)F^{-1}(n/d)-\sum_{d|n,d!=1}^nF(d)F^{-1}(n/d)=F^{-1}(n) \]

有:

\[F^{-1}(ab)=\sum_{d|ab}^{ab}F(d)F^{-1}(ab/d)-\sum_{d|ab,d!=1}^{ab}F(d)F^{-1}(ab/d) \]

\[F^{-1}(ab)=e(ab)-\sum_{d|ab,d!=1}^{ab}F(d)F^{-1}(ab/d) \]

\[F^{-1}(ab)=0-\sum_{d|ab,d!=1}^{ab}F(d)F^{-1}(ab/d) \]

\[=-\sum_{d|ab,d!=1}^{ab}F(d)F^{-1}(ab/d) \]

\[=-\sum_{i|a}^{a}\sum_{j|b,ij!=1}^{b}F(ij)F^{-1}(ab/ij) \]

\[=-\sum_{i|a}^{a}\sum_{j|b,ij!=1}^{b}F(i)F^{-1}(j)F^{-1}(a/i)F(b/j) \]

\[=-\sum_{i|a}^{a}F(i)F^{-1}(a/i)\sum_{j|b,ij!=1}^{b}F^{-1}(j)F(b/j) \]

\[=F(1)F^{-1}(a)F^{-1}(1)F(b)-\sum_{i|a}^{a}F(i)F^{-1}(a/i)\sum_{j|b}^{b}F^{-1}(j)F(b/j) \]

\[=F^{-1}(a)F(b)-e(a)*e(b) \]

\[=F^{-1}(a)F(b) \]

证毕


莫比乌斯反演:

设:

\[F(n)=\sum_{d|n}^nf(d) \]

显然:

\[F(n)=\sum_{d|n}^nf(d)*1 \]

即:

\[F=I*f \]

那么:

\[f=I^{-1}*F \]

现在只需要求 \(I^{-1}\) 即可通过 \(F\) 反演出 \(f\) 。

令 \(\mu=I^{-1}\),显然 \(\mu\) 是积性函数。

先从 \(\mu(p^k)\) 入手:

当 \(k=0\) 时:

\[e(1)=I(1)*\mu(1)=1 \]

因此 \(\mu(1)=1\)

\(k=1\) 时:

\[e(p)=I(1)*\mu(p)+I(p)*\mu(1)=0 \]

\[\mu(p)+\mu(1)=0 \]

\[\mu(p)=-1 \]

\(k=2\) 时:

\[e(p^2)=I(1)*\mu(p^2)+I(p)*\mu(p)+I(p^2)*\mu(1)=0 \]

\[\mu(p^2)+\mu(p)+\mu(1)=0 \]

\[\mu(p^2)+0=0 \]

\[\mu(p^2)=0 \]

\(k>2\) 时,数学归纳法可证 \(\mu(p^k)=0\)

因此,若:

\[n=pri_1^{k_1}*pri_2^{k_2}*... \]

则:

\[\mu(n)=\begin{cases} 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ [\ \exists\ k_i>1]\\ (-1)^{\sum k}\ \ \ \ \ [\ \forall\ k_i<=1]\\ \end{cases}\]

这就有了莫反的第一种形式:

\[F(n)=\sum_{d|n}^nf(d) ⟺ f(n)=\sum_{d|n}^n\mu(d)F(n/d)\ \ \ (1) \]

也是最常用的形式。

还有倍数形式:

\[F(n)=\sum_{n|d}^nf(d) ⟺ f(n)=\sum_{n|d}^n\mu(d)F(d/n)\ \ \ (2) \]

可以左式代入右式中证明,更简单的方法是像二项式反演那样,直接把转移写成矩乘的形式,转置一下即可。

以上两个式子由于转移方向单一,而且复杂度没什么优化,所以一般可以直接一层容斥解决,不需要莫反

更有用的是嵌入式莫反:

因为:

\[I*\mu=e \]

所以:

\[\sum_{d|n}^n\mu(d)=[n=1] \]

由于:

\[[n|m][m/n=1]=[n=m] \]

所以:

\[[n|m]\sum_{d|m/n}^{m/n}\mu(d)=[n=m] \]


莫比乌斯反演与整除分块:

  • (1)求:

\[\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=1] \]

我们使用嵌入式反演,有:

\[\sum_{d|n}^n\mu(d)=[n=1] \]

\[\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=1]=\sum_{i=1}^n\sum_{j=1}^m\sum_{d|gcd(i,j)}^{gcd(i,j)}\mu(d) \]

由于:

\[[d|gcd(i,j)]=[d|i][d|j] \]

因此:

\[\sum_{i=1}^n\sum_{j=1}^m[gcd=1]=\sum_{d}^{min(n,m)}\mu(d)\sum_{d|i}^n\sum_{d|j}^m1 \]

\[\sum_{i=1}^n\sum_{j=1}^m[gcd=1]=\sum_{d}^{min(n,m)}\mu(d) \lfloor n/d \rfloor \lfloor m/d \rfloor \]

预处理前缀和,整除分块即可在 \(O(\sqrt n)\) 时间内求解

  • (2)求:

\[\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=k] \]

我们使用嵌入式反演,有:

\[[n|k]\sum_{d|k/n}^{k/n}\mu(d)=[n=k] \]

\[\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=k]=\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)|k]\sum_{d|k/gcd(i,j)}^{k/gcd(i,j)}\mu(d) \]

因此:

\[\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=k]=\sum_{d=1}^{min(n,m)}\mu(d)\sum_{d|i}^{n/k}\sum_{d|j}^{m/k}1 \]

\[\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=k]=\sum_{d=1}^{min(n,m)}\mu(d) \lfloor \frac n{kd} \rfloor \lfloor \frac m{kd} \rfloor \]

  • (3)求:

\[\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)\in prime] \]

即:

\[\sum_{k \in prime}^{min(n,m)}\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=k] \]

\[=\sum_{k \in prime}^{min(n,m)}\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)|k]\sum_{d|k/gcd(i,j)}^{k/gcd(i,j)}\mu(d) \]

\[=\sum_{k \in prime}^{min(n,m)}\sum_{d=1}^{min(n/k,m/k)}\mu(d)\sum_{d|i}^{n/k}\sum_{d|j}^{m/k}1 \]

\[=\sum_{k \in prime}^{min(n,m)}\sum_{d=1}^{min(n/k,m/k)}\mu(d)\sum_{kd|i}^{n}\sum_{kd|j}^{m}1 \]

另 \(d=kd\) ,枚举新的 \(d\):

\[\sum_{k \in prime}^{min(n,m)}\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=k]=\sum_{d=1}^{min(n,m)}\sum_{k \in prime,k|d}^{min(n,m)}\mu(d/k)\sum_{d|i}^{n}\sum_{d|j}^{m}1 \]

\[=\sum_{d=1}^{min(n,m)}\sum_{k \in prime,k|d}^{min(n,m)}\mu(d/k) \lfloor n/d \rfloor \lfloor m/d \rfloor \]

\[=\sum_{d=1}^{min(n,m)} \lfloor n/d \rfloor \lfloor m/d \rfloor \sum_{k \in prime,k|d}^{min(n,m)}\mu(d/k) \]

将预处理 \(\mu(d)\) 的前缀和改为预处理 \(\sum_{k \in prime,k|d}^{min(n,m)}\limits \mu(d/k)\) 即可。

  • (4)求:

\[\prod_{i=1}^n\prod_{j=1}^n\frac{lcm(i,j)}{gcd(i,j)} \]

显然:

\[\prod_{i=1}^n\prod_{j=1}^n\frac{lcm(i,j)}{gcd(i,j)}=\prod_{i=1}^n\prod_{j=1}^n\frac{i*j}{gcd(i,j)^2} \]

\[=(\prod_{i=1}^n\prod_{j=1}^ni*j)*(\prod_{i=1}^n\prod_{j=1}^ngcd(i,j))^{-2} \]

\[=(\prod_{i=1}^n(i^n*n!))*(\prod_{k=1}^{n}k^{-2*(\sum_{i=1}^{n/k}\limits \sum_{j=1}^{n/k}\limits [gcd(i,j)=k])}) \]

\[=(n!)^{2n}*(\prod_{k=1}^{n}k^{-2*(\sum_{d=1}^{n/k}\limits\mu(d) \lfloor \frac n{kd} \rfloor^2)}) \]

如果对 \(\lfloor \frac n{kd} \rfloor\) 整除分块,分别对每个 \(d\) 求出对应的 \(\sum_{d=1}^{n/k}\limits\mu(d) \lfloor \frac n{kd} \rfloor^2)\),时间复杂度就是 \(O(n \sqrt n)\) 的。

我们可以直接对 \(n/k\) 整除分块,求出 \(\prod_{k=1}^{n}k^{-2*(\sum_{d=1}^{n/k}\limits\mu(d) \lfloor \frac n{kd} \rfloor^2)}\) ,时间复杂度就约为 \(O(\sqrt n*\sqrt n)=O(n)\)

  • (5)求:

\[\sum_{i=1}^n \sum_{j=1}^md(ij) \]

有等式:

\[d(ij)=\sum_{x|i}\sum_{y|j}[gcd(x,y)==1] \]

对于每一个质因数讨论,令 \(k_x\) 表示最大的 \(prime^k|x\)。

用 \(d\) 表示所枚举的约数,设 \(k_i>k_j\)。

那么若\(k_y=0\),则 \(k_d=k_x\) ,若 \(k_x=0\),则 \(k_d=k_i+k_y\)。

显然这样可以表示出所有约数,等式成立。

\[\sum_{i=1}^n \sum_{j=1}^md(ij)=\sum_{i=1}^n \sum_{j=1}^m\sum_{x|i}\sum_{y|j}[gcd(x,y)==1] \]

\[=\sum_{i=1}^n \sum_{j=1}^m\sum_{x|i}\sum_{y|j}\sum_{d|gcd(x,y)}\mu(d) \]

\[=\sum_{x=1}^n \sum_{y=1}^m\lfloor \frac {n}{x} \rfloor\lfloor \frac {m}{y} \rfloor \sum_{d|gcd(x,y)}\mu(d) \]

\[=\sum_{i=1}^n \sum_{j=1}^m\lfloor \frac {n}{i} \rfloor\lfloor \frac {m}{j} \rfloor \sum_{d|gcd(x,y)}\mu(d) \]

\[=\sum_d^{min(n,m)}\mu(d)\sum_{i=1}^{\lfloor \frac n d\rfloor }\sum_{j=1}^{\lfloor \frac m d \rfloor}\lfloor \frac {n}{id} \rfloor\lfloor \frac {m}{jd} \rfloor \]

\[=\sum_d^{min(n,m)}\mu(d)\sum_{i=1}^{\lfloor \frac n d\rfloor }\lfloor \frac {n}{id} \rfloor\sum_{j=1}^{\lfloor \frac m d \rfloor}\lfloor \frac {m}{jd} \rfloor \]

整除分块即可

[SDOI2008] 仪仗队

#include<bits/stdc++.h>
using namespace std;
int q;
long long mu[50005];
int pri[50005],top;
bool vis[50005];
inline void init(){
	mu[1]=1;
	for(int i=2;i<=5e4;i++){
		if(!vis[i])pri[++top]=i,mu[i]=-1;
		for(int j=1;j<=top&&pri[j]*i<=5e4;j++){
			vis[i*pri[j]]=1;
			if(i%pri[j]==0)break;
			mu[i*pri[j]]=-mu[i];
		}
	}for(int i=1;i<=5e4;i++)mu[i]+=mu[i-1];
}
inline long long solve(int n,int m){
	long long res=0;
	for(int l=1,r=0;l<=n&&l<=m;l=r+1){
		r=min(n/(n/l),m/(m/l));
		res+=1ll*(mu[r]-mu[l-1])*(n/l)*(m/l);
	}return res;
}
int main(){
	init();
	scanf("%d",&q);if(q==1){puts("0");return 0;}
	printf("%lld",solve(q-1,q-1)+2);
//	scanf("%d",&q);
//	while(q--){
//		int n,m;
//		scanf("%d%d",&n,&m);
//	}

	return 0;
}



[POI2007]ZAP-Queries

#include<bits/stdc++.h>
using namespace std;
int q;
long long mu[50005];
int pri[50005],top;
bool vis[50005];
inline void init(){
	mu[1]=1;
	for(int i=2;i<=5e4;i++){
		if(!vis[i])pri[++top]=i,mu[i]=-1;
		for(int j=1;j<=top&&pri[j]*i<=5e4;j++){
			vis[i*pri[j]]=1;
			if(i%pri[j]==0)break;
			mu[i*pri[j]]=-mu[i];
		}
	}for(int i=1;i<=5e4;i++)mu[i]+=mu[i-1];
}
inline long long solve(int n,int m,int d){
	long long res=0;
	for(int l=1,r=0;l<=n&&l<=m;l=r+1){
		r=min(n/(n/l),m/(m/l));
		res+=1ll*(mu[r]-mu[l-1])*(n/l/d)*(m/l/d);
	}return res;
}
int main(){
	init();
	scanf("%d",&q);
	while(q--){
		int n,m,d;
		scanf("%d%d%d",&n,&m,&d);
		printf("%lld\n",solve(n,m,d));
	}

	return 0;
}



YY的GCD

#include<bits/stdc++.h>
using namespace std;
int t,n,m;
long long mu[10000005],sum[10000005],f[10000005];
int pri[10000005],top;
bool vis[10000005];
inline void init(){
	mu[1]=1;
	for(int i=2;i<=1e7;i++){
		if(!vis[i])pri[top++]=i,mu[i]=-1;
		for(int j=0;j<top&&i*pri[j]<=1e7;j++){
			vis[i*pri[j]]=1;
			if(i%pri[j]==0)break;
			mu[i*pri[j]]=-mu[i];
		}
	}
	for(int i=0;i<top;i++){
		for(int j=1;j*pri[i]<=1e7;j++)f[j*pri[i]]+=mu[j];
	}
	for(int i=1;i<=1e7;i++)sum[i]=sum[i-1]+f[i];
}
long long solve(){
	long long res=0;
	if(n>m)swap(n,m);
	for(int l=1,r=0;l<=n;l=r+1){
		r=min(n/(n/l),m/(m/l));
		res+=(sum[r]-sum[l-1])*(n/l)*(m/l);
	}return res;
}
int main(){
	init();//puts("000");
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		printf("%lld\n",solve());
	}

	return 0;
}


Product

#include<bits/stdc++.h>
using namespace std;
long long fac;
const long long md=104857601,phi=104857600;
int pri[1000005],top,mu[1000005];
bool vis[1000005];
inline void init(int n){
	mu[1]=1;
	for(int i=2;i<=n;i++){
		if(!vis[i])pri[++top]=i,mu[i]=-1;
		for(int j=1;j<=top&&i*pri[j]<=n;j++){
			vis[i*pri[j]]=1;
			if(i%pri[j]==0)break;
			mu[i*pri[j]]=-mu[i];
		}
	}
	fac=1;
	for(int i=1;i<=n;i++)fac=fac*i%md;
	for(int i=1;i<=n;i++)mu[i]+=mu[i-1];
}
inline long long pwr(long long x,long long y){
	long long res=1;
	while(y){
		if(y&1)res=res*x%md;
		x=x*x%md;y>>=1;
	}return res;
}
inline long long calc2(int n){
	long long res=0;
	for(int l=1,r=0;l<=n;l=r+1){
		r=n/(n/l);
		res=(res+1ll*(n/l)*(n/l)%phi*(mu[r]-mu[l-1]))%phi;
	}return (res+phi)%phi;
}
inline long long calc(int n){
	long long res=1;
	for(int l=1,r=0;l<=n;l=r+1){
		r=n/(n/l);fac=1;
		for(int i=l;i<=r;i++)fac=fac*i%md;
		res=res*pwr(fac*fac%md,calc2(n/l))%md;
	}return res;
}
int main(){
	int n;
	scanf("%d",&n);
	init(n);
	long long ans=pwr(fac*fac%md,n);
	printf("%lld",ans*pwr(calc(n),md-2)%md);

	return 0;
}



[SDOI2015]约数个数和

#include<bits/stdc++.h>
using namespace std;
int T;
long long mu[50005],s[50005];
int pri[50005],top;
bool vis[50005];
inline void init(){
	mu[1]=1;
	for(int i=2;i<=50000;i++){
		if(!vis[i])pri[++top]=i,mu[i]=-1;
		for(int j=1;j<=top&&i*pri[j]<=50000;j++){
			vis[i*pri[j]]=1;
			if(i%pri[j]==0)continue;
			mu[i*pri[j]]=-mu[i];
		}mu[i]+=mu[i-1];
	}
	for(int i=1;i<=50000;i++){
		for(int l=1,r;l<=i;l=r+1){
			r=i/(i/l);
			s[i]+=i/l*(r-l+1);
		}
	}
}
inline long long solve(int n,int m){
	long long res=0;
	for(int l=1,r;l<=n&&l<=m;l=r+1){
		r=min(n/(n/l),m/(m/l));
		res+=(mu[r]-mu[l-1])*s[n/l]*s[m/l];
	}return res;
}
int main(){
	scanf("%d",&T);init();
	while(T--){
		int n,m;
		scanf("%d%d",&n,&m);
		printf("%lld\n",solve(n,m));
	}

	return 0;
}
上一篇:认识PyQt、菜单栏、工具栏、状态栏


下一篇:PyQt5 入门系列 目录