莫比乌斯反演

莫比乌斯反演

前置知识

  1. 积性函数
  2. 欧拉函数莫比乌斯函数
  3. 线性筛
  4. 数论分块

积性函数

指对于所有互质的整数a和b有f(ab)=f(a)f(b)的函数。

性质

1.x=p1a1×p2a2...×pkak,f(x)=f(p1a1)×f(p2a2)×...f(pkak)2.f(x),g(x),f(x)g(x)3.dnf(d)dmg(d)=d1nd2mf(d1)g(d2)1.若x=p_1^{a_1}\times p_2^{a_2}...\times p_k^{a_k},f(x)=f(p_1^{a_1})\times f(p_2^{a_2})\times...f(p_k^{a_k})\\2.如果两个函数f(x),g(x)均是可乘函数,则f(x)g(x)也是可乘函数\\3.\sum_{d|n} f(d) * \sum_{d|m}g(d) = \sum_{d_1|n} \sum_{d_2|m}f(d_1) * g(d_2)

欧拉函数

ϕ(n)=i=1n[gcd(i,n)==1]nnn,n=p1a1×p2a2...×pkakϕ(n)=n(1p1)(1p2)...(1pk)定义\phi(n)=\sum_{i=1}^n[gcd(i,n)==1]\\ 即在小于等于n中的正整数中与n互质的数字个数\\ 将n质因数分解,n=p_1^{a_1}\times p_2^{a_2}...\times p_k^{a_k}\\ \phi(n)=n*(1-p_1)(1-p_2)...(1-p_k)

欧拉函数是积性函数

欧拉函数的线性筛求法

φ(n)p,φ(np)pn,φ(np)=φ(n)pφ(np)=φ(n)(p1)当已知\varphi(n)时\\ p为质数,\varphi(n*p)有两种情况\\ 若p|n,\varphi(n*p)=\varphi(n)*p\\ 否则,\varphi(n*p)=\varphi(n)*(p-1)

n=p1p2...pkφ(n)=n(11p1)(11p2)...(11pk)qφ(nq)=(nq)(11p1)(11p2)...(11pk)qφ(nq)=(nq)(11p1)(11p2)...(11pk)(11q)原理如下\\ 记 n = p_1 * p_2 * ... * p_k接下来讨论在原来的基础上增加素数如何计算\\\varphi(n) = n * \prod(1 - \frac{1}{p_1}) (1 - \frac{1}{p_2})...(1 - \frac{1}{p_k}) \\假如加了一个素数 q,如果出现过\\\varphi(n * q) = (n * q) * \prod(1 - \frac{1}{p_1}) (1 - \frac{1}{p_2})...(1 - \frac{1}{p_k}) \\假如加了一个素数 q,如果没出现过\\\varphi(n * q) = (n * q) * \prod(1 - \frac{1}{p_1}) (1 - \frac{1}{p_2})...(1 - \frac{1}{p_k}) (1 - \frac{1}{q}) \\

bj[1]=1;
phi[1]=1;
for(int i=2;i<=5e4;i++){
    if(bj[i]==0){p[++k]=i;phi[i]=1;}
    for(int j=1;j<=k&&i*p[j]<=5e4;j++){
        bj[i*p[j]]=1;
        if(i%p[j]==0){
            phi[i*p[j]]=phi[i]*p[j];
            break;
        }
        else
            phi[i*p[j]]=phi[i]*(p[j]-1);
    }
}

莫比乌斯函数

μ(n)={1n=1(1)knn=p1p2...pk0n定义 \mu(n) = \begin{cases} 1 & n = 1 \\ (-1)^k & n无平方因数,记 n = p_1 * p_2 * ... * p_k \\ 0 & n有平方因数 \end{cases}

莫比乌斯函数为积性函数

莫比乌斯函数的线性筛求法

μ(n)p,μ(np)pn,μ(np)=0μ(np)=μ(n)当已知\mu(n)时\\ p为质数,\mu(n*p)有两种情况\\ 若p|n,\mu(n*p)=0\\ 否则,\mu(n*p)=-\mu(n)

bj[1]=1;
mu[1]=1;
for(int i=2;i<=5e4;i++){
    if(bj[i]==0){p[++k]=i;mu[i]=-1;}
    for(int j=1;j<=k&&i*p[j]<=5e4;j++){
        bj[i*p[j]]=1;
        if(i%p[j]==0){
            mu[i*p[j]]=0;
            break;
        }
        else
            mu[i*p[j]]=-mu[i];
    }
}

欧拉函数和莫比乌斯函数的关系

φ(n)n=dnμ(d)d\frac{\varphi(n)}{n} = \sum_{d|n} \frac{\mu(d)}{d}

数论分块

i=1n[ni]求解\sum_{i=1}^n[\frac n i]

取n=11

[111]=11[\frac{11}{1}] = 11

$[\frac{11}{2}] = 5 $

$[\frac{11}{3}] = 3 $

[114]=2,[115]=2[\frac{11}{4}] = 2, [\frac{11}{5}] = 2

[116]=1,[117]=1,[118]=1,[119]=1,[1110]=1,[1111]=1[\frac{11}{6}] = 1, [\frac{11}{7}] = 1, [\frac{11}{8}] = 1, [\frac{11}{9}] = 1, [\frac{11}{10}] = 1, [\frac{11}{11}] = 1

默认取下整,会有一段段的结果相同

当i小于等于n\sqrt n会有n\sqrt n个不同结果

当i大于n\sqrt n[nn][\frac{n}{\sqrt n}]值域小于n\sqrt n

故最多有2n2\sqrt n个不同取值

我们只要求出每一段区间的左右端点即可

而每一段的左端点应是上一段的右端点+1

故我们只要能由该段左端点求出该段右端点即可

用l,r,分别表示区间左右端点

[nr]=[nl][\frac n r]=[\frac n l]

r=[n[nl]]r=[\frac{n}{[\frac n l]}]

for(long long l=1,r;l<=b;l=r+1){
    r=n/(n/l);
    ans+=(r-l+1)*(n/l)%mod;
    ans%=mod;
}
例题Calculating

f(x)为x的约数个数

容斥得i=lrf(i)=i=1rf(i)i=1l1f(i)\sum_{i=l}^rf(i)=\sum_{i=1}^rf(i)-\sum_{i=1}^{l-1}f(i)

我们只要解决i=1nf(i)\sum_{i=1}^nf(i)即可

显然可以转换为枚举每一个数是多少个数的约数i=1n[ni]\sum_{i=1}^n[\frac n i]

数论分块即可

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
long long read(){
	long long x=0,y=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')y=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*y;
}
int main(){
	long long a,b,ans=0;
	a=read()-1;b=read();
	for(long long l=1,r;l<=b;l=r+1){
		r=b/(b/l);
		ans+=(r-l+1)*(b/l)%mod;
		ans%=mod;
	}
	for(long long l=1,r;l<=a;l=r+1){
		r=a/(a/l);
		ans-=(r-l+1)*(a/l)%mod;
		ans%=mod;
	}
	printf("%lld",(ans%mod+mod)%mod);
	return 0;
}

接下来我们考虑这么一个式子如何数论分块,这也是莫比乌斯反演的题中经常要使用的

i=1min(n,m)[ni][mi]\sum_{i=1}^{min(n,m)}[\frac n i][\frac m i]

上面我们已经分析过可以求出a\sqrt a[ai][\frac a i]相同的区间

我们考虑对n,mn,m一起数论分块,即计算出某段区间内ni\frac n i两两相同且mi\frac m i两两相同

复杂度仍是O(n)O(\sqrt n)

for(int l=1,r;l<=min(n,m);l=r+1){
    r=min(n/(n/l),m/(m/l));
    ans+=(a/l)*(m/l);
}

莫比乌斯反演

核心式

F(n)=dnf(d)f(n)=dnμ(d)F(nd)F(n)=ndf(d)f(n)=ndμ(dn)F(d)约数式:\\ 若有 \\ F(n) = \sum_{d|n}f(d) \\ 则有 \\ f(n) = \sum_{d|n}\mu(d)F(\frac{n}{d}) \\ 倍数式:\\ 若有\\ F(n) = \sum_{n|d}f(d)\\ 则有\\ f(n) = \sum_{n|d}\mu(\frac{d}{n})F(d)

dnμ(d)F(nd)=dnμ(d)d1ndf(d1)d1=d1nf(d1)dnd1μ(d)d1f(d1)dnd1μ(d)nd1=11d1=n=f(n)1=f(n)\sum_{d|n}\mu(d)F(\frac{n}{d}) \\ = \sum_{d|n}\mu(d) \sum_{d_1 | \frac{n}{d}}f(d_1) \\ 交换枚举次序,先枚举 d_1 \\ = \sum_{d_1|n}f(d_1) \sum_{d | \frac{n}{d_1}}\mu(d) \\ 此时我们可以看到对于每个枚举的 d_1,此时的 f(d_1) 是个常数,从而 \\ \sum_{d | \frac{n}{d_1}}\mu(d) 仅当 \frac{n}{d_1} = 1时有非零值为 1 \\ 此时 d_1 = n \\ 代入原式 = f(n) * 1 = f(n),证毕

例题[SDOI2015]约数个数和

小结论

d(x)xd(ij)=xiyj[gcd(x,y)==1]p,ipa,jpbpk,k<=a,ipk,k>a,ipjpkad(x)表示x的约数个数\\ d(i*j)=\sum_{x|i}\sum_{y|j}[gcd(x,y)==1]\\ 简单证明:\\ 对于一个质数p,i里有p^a,j里有p^b,我们要选出p^k,钦定做出如下选择\\ 若k<=a,在i中选出p^k,若k>a,默认选满i的所有p,在j中选p^{k-a}\\ 按照这样的选法能不重不漏的选出所有约数

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

把x,y往前提x=1ny=1m[nx][my][gcd(x,y)==1]\sum_{x=1}^n\sum_{y=1}^m[\frac n x][\frac m y][gcd(x,y)==1]

开始莫比乌斯反演套路

f(k)=x=1ny=1m[nx][my][gcd(x,y)==k]f(k)=\sum_{x=1}^n\sum_{y=1}^m[\frac n x][\frac m y][gcd(x,y)==k]

F(k)=kdf(d)F(k)=\sum_{k|d}f(d)

F(k)=x=1ny=1m[nx][my][kgcd(x,y)]F(k)=\sum_{x=1}^n\sum_{y=1}^m[\frac n x][\frac m y][k|gcd(x,y)]

将k提出来

F(k)=x=1[nk]y=1[mk][nkx][mky][1gcd(x,y)]F(k)=\sum_{x=1}^{[\frac n k]}\sum_{y=1}^{[\frac m k]}[\frac n {kx}][\frac m {ky}][1|gcd(x,y)]

F(k)=x=1[nk]y=1[mk][nkx][mky]F(k)=\sum_{x=1}^{[\frac n k]}\sum_{y=1}^{[\frac m k]}[\frac n {kx}][\frac m {ky}]

由莫比乌斯反演

f(x)=xdμ(dx)F(x)f(x)=\sum_{x|d}\mu(\frac d x)F(x)

f(1)=d=1μ(d)F(d)=d=1μ(d)x=1[nd]y=1[md][ndx][mdy]f(1)=\sum_{d=1}\mu(d)F(d)=\sum_{d=1}\mu(d)\sum_{x=1}^{[\frac n d]}\sum_{y=1}^{[\frac m d]}[\frac n {dx}][\frac m {dy}]

我们用数论分块预处理出g(u,v)=x=1uy=1v[ux][vy]g(u,v)=\sum_{x=1}^u\sum_{y=1}^v[\frac u {x}][\frac v {y}]

f(1)=d=1μ(d)g([nd],[md])f(1)=\sum_{d=1}\mu(d)g([\frac n d],[\frac m d])

这个可以再一次数论分块

故复杂度O(Tn)O(T\sqrt n)

#include<bits/stdc++.h>
using namespace std;
const int maxn=50005,maxm=50005;
int k=0;
int p[maxn],mu[maxn];
bool bj[maxn];
long long s[maxn];
int read(){
	int x=0,y=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')y=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*y;
}
void pre(){
	bj[1]=1;
	mu[1]=1;
	for(int i=2;i<=5e4;i++){
        if(bj[i]==0){p[++k]=i;mu[i]=-1;}
        for(int j=1;j<=k&&i*p[j]<=5e4;j++){
        	bj[i*p[j]]=1;
        	if(i%p[j]==0){
        		mu[i*p[j]]=0;
				break;
			}
			else
				mu[i*p[j]]=-mu[i];
       	}
	}
	for(int i=1;i<=5e4;i++)mu[i]+=mu[i-1];
	for(int x=1;x<=5e4;x++){
		long long res=0;
		for(long long l=1,r;l<=x;l=r+1){
			r=x/(x/l);
			res+=(r-l+1)*(x/l);
		}
		s[x]=res;
	}	
}
int main(){
	pre();
	int t;
	t=read();
	while(t--){
		int n,m;
		n=read();m=read();
		if(n>m)swap(n,m);
		long long ans=0;
		for(int l=1,r;l<=n;l=r+1){
			r=min(n/(n/l),m/(m/l));
			ans+=(mu[r]-mu[l-1])*s[n/l]*s[m/l];
		}
		printf("%lld\n",ans);
	}
	return 0;
}

练习题

[POI2007]ZAP-Queries

[NOI2010]能量采集

[国家集训队]Crash的数字表格 / JZPTAB

按难度排序

总结

碰到莫比乌斯反演的题,把答案表示出来

强行套上gcd==x这样的一个判断形式

再设函数根据需要看是用莫比乌斯反演的约数式还是倍数式

然后用改变枚举顺序等方法化简式子,最后可能用到数论分块降低复杂度