莫比乌斯反演与狄利克雷卷积

莫比乌斯反演

数论函数

列举几个常见数论函数

  1. φ(n),欧拉函数,表示1n中与n互质的数的个数
  2. d(n),表示n的约数个数,具体设n=p1c1p2c2pmcm(p1,p2),则d(n)=i=1m(ci+1)
  3. ,下取整函数,abc=abc
  4. σ(n),表示n的约数和,也即σ(n)=i=1mpci+11pi1
  5. I(n),恒等函数,值恒为1
  6. id(n),单位函数,id(n)=n
  7. 单位函数ϵ(n)=[n=1]
    先看几个约数函数的常见性质

d|ndμ(nd)=φ(n)

d|nφ(d)=n

d|nμ(d)=[n=1]

d(AB)=x|Ay|B[gcd(x,y)=1]

积性函数

定义1:若对于函数f来说,使得对于满足gcd(x,y)=1的任意正整数x,y,满足f(xy)=f(x)f(y)

则称f为积性函数.

例如:φ,d,μ,id,I,σ都是积性函数

定义2:若对于函数f,若任意正整数x,y都有f(xy)=f(x)f(y),则称f为完全积性函数

例如:I,id,σ,d是完全积性函数

狄利克雷卷积

定义两个数论函数f,g的狄利克雷卷积t=fg,使得:t(n)=ij=nf(i)g(j)

性质:

  1. 交换律:fg=gf
  2. 结合律:(fg)t=f(gt)
  3. 分配律:t(f+g)=tf+tg
  4. 标量乘法:(x·f)g=xfg
  5. 逆元:对于任意函数f(1)0,有函数f的逆g满足fg=ϵ

讨论一下逆的求法,对于函数f的逆g,满足

g(n)=1f(1)([n=1]i|n,ing(i)f(ni))

证明:将g带入原式,设t=fg,有

t(n)=ij=nf(i)g(j)=ij=nf(i)1f(1)([n=1]k|j,kjg(k)f(jk))

n=1时显然成立,在n1时,原式等价于ij=nf(i)k|j,kjg(k)f(jk)f(1),显然此式每一对ij能抵消,分子为0,故得证

莫反及其应用

莫比乌斯反演是关于莫比乌斯函数的,具体的证明可以由容斥原理导出,也可以看这里

莫比乌斯反演的两种形式

形式1:

f(n)=d|ng(d)g(n)=d|nμ(d)f(nd)

形式2:

f(n)=n|dg(d)n|dμ(dn)f(d)

实际应用:

例1:P2568GCD

给定正整数 n,求 1x,yngcd(x,y) 为素数的数对 (x,y) 有多少对。

题意即为求

S=pni=1nj=1n[gcd(i,j)=p]

=pni=1npj=1np[gcd(i,j)=1]

f(i)=i=1aj=1b[gcd(i,j)=i],g(i)=i|df(d),也即S=pnf(p)

g(n)=n|di=1aj=1b[gcd(i,j)=d]=i=1aj=1b[n|gcd(i,j)]=i=1anj=1bn[1|gcd(i,j)]=anbn

所以由莫比乌斯反演定理得f(p)=p|dμ(dp)g(d)=1iμ(ip)g(i)=1iμ(i)nip2

S=pn1iμ(i)nip2,设ip=T,则

S=T=1nnT2p|TTμ(Tp)

预处理μ前缀和,数论分块即可,后面的式子可以在筛质数的时候用埃氏筛求出p的集合即可

例2:P2398

给定n,求:i=1nj=1ngcd(i,j)

原式=

d=1ni=1nj=1nd[gcd(i,j)=d]=d=1di=1ndj=1nd[gcd(i,j)=1]=d=1ndf(d)

=d=1ndi=1ndμ(i)nid2

一样设T=id,则原式=

T=1nnT2i|TTiμ(i)

因为d|nφ(d)=n,所以将欧拉函数带入莫比乌斯反演公式,可以得到φ(n)=d|ndμ(nd),仔细观察,也即我们最终结果后面的那坨式子等价于φ(T)

故最终S=T=1nT2φ(T),此时预处理出φ的前缀和,结合数论分块,就可以做到O(n+qn)的复杂度(q为询问次数)

例三:

给出 n,m 和一个长度为 n1 的序列 x,保证 xi 互不相同。

i1=1mx1i2=1mmax{x1,x2}i3=1mmax{x2,x3}in=1mxn1[gcd(i1,i2,i3in)=1]

答案对 998244353 取模。

f(n)=i1=1mx1i2=1mmax{x1,x2}i3=1mmax{x2,x3}in=1mxn1[gcd(i1,i2,i3in)=n],g(n)=n|df(d)

g(n)展开为:

g(n)=i1=1mx1i2=1mmax{x1,x2}i3=1mmax{x2,x3}in=1mxn1[n|gcd(i1,i2,i3in)]

除过去,变成

g(n)=i1=1mnx1i2=1mnmax{x1,x2}i3=1mnmax{x2,x3}in=1mnxn1[1|gcd(i1,i2,i3in)]

假若令xn=,x0=xn,则式子可以改写为

g(n)=i=1nmnmax{xi,xi1}

分子可以预处理比较,设比较后为ai,bi=mai

g(n)=i=1nmnai=i=1nbin

因为我们所求为:

f(1)=i=1min1in{bi}μ(i)g(i)

上面那个min看上去很恶心,预处理改成d

展开变成:

f(1)=i=1dμ(i)k=1nbki

这个式子是一个扩展形式的数论分块

例四

由于出题人懒得写背景了,题目还是简单一点好。

输入一个整数 n 和一个整数 p,你需要求出:

(i=1nj=1nijgcd(i,j))modp

其中 gcd(a,b) 表示 ab 的最大公约数。

对于100%的数据,5×108p1.1×109n1010p 为质数。

一道比较套路的题

原式=

k=1nki=1nj=1n[gcd(i,j)=k]ij

f(x)=i=1nj=1n[gcd(i,j)=x]ij,g(x)=x|df(d)

展开g(x),有

g(x)=i=1nj=1n[x|gcd(i,j)]ij=x2i=1nxij=1nxj=x2i=1nxinx(nx+1)2=x2nx2(nx+1)24

所以回带,原式=

k=1nkf(k)=k=1nki=1nkμ(i)g(ik)=k=1nki=1nkμ(i)(ik)2nik2(nik+1)24

=T=1nT2nT2(nT+1)24k|Tkμ(Tk)=T=1nT2nT2(nT+1)24φ(T)

T2φ(T)的部分用杜教筛/Min25筛,另一部分数论分块即可

例五

d(x)x 的约数个数,给定 n,m,求

i=1nj=1md(ij)

对于 100% 的数据,1T,n,m50000

考虑拆开d函数

引理:d(ij)=x|iy|j[gcd(x,y)=1]

证明:

考虑从质因数的角度,考虑简化版情况

  1. i,j互质,此时右式的gcd(x,y)显然成立,而左式的d(ij)=d(i)d(j),成立

  2. i=pa,j=pb,pprimes,此时显然有d(ij)=a+b+1,而左式当且仅当x=1y=1,再加上x=1,y=1的情况,也有a+b+1个解

  3. 一般情况下,可以将ij分解质因数,然后因为左式是完全积性函数,仍成立,而右式根据乘法原理合并若干个a+b+1,就正好可以合并出若干情况,其中乘1就是不考虑这个位的影响,a+b就是考虑这个质因数在累加上[1,a+b],得证

那么原式即为

i=1nj=1mx|iy|j[gcd(x,y)=1]

=x=1ny=1m[gcd(x,y)=1]nxmy

f(x)=i=1nj=1m[gcd(i,j)=x]nimj,g(n)=n|df(d)

展开g(x),得到

g(x)=i=1nj=1m[x|gcd(i,j)]nimj=i=1nxj=1mxnximxj

回带,原式即为求f(1)=i=1nμ(i)g(i)

考虑如何求解g,观察可得

g(x)=i=1nxj=1mxnximxj

n=nx,m=mx,则

g(x)=i=1nnij=1mmj

那么两段式子明显可以预处理,设S(n)=i=1nni,则有

f(1)=i=1nμ(i)S(ni)S(mi)

明显的,后半截的两个S可以数论分块

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 50050
#define int long long
int mu[N], s[N], n, m, t, prime[N], v[N];
int get(int n,int x) {
	return n / (n / x);
}
void init() {
	for (int i = 1; i <= N - 5; i++)mu[i] = 1;
	for (int i = 2; i <= N - 5; i++) {
		if (!v[i]) {
			v[i] = 1;
			mu[i] = -1;
			for (int j = 2; i * j <= N - 5; j++) {
				mu[i * j] *= -1;
				v[i * j] = 1;
				if (j % i == 0)mu[i * j] = 0;
			}
		}
	}
//	for (int i = 1; i <= 20; i++)cout << mu[i] << " ";
//	cout << endl;
	for (int i = 1; i <= N - 5; i++)mu[i] += mu[i - 1];
	for (int i = 1; i <= N - 5; i++) {
		for (int l = 1, r; l <= i; l = r + 1) {
			r = get(i, l);
			s[i] += (r - l + 1) * (i / l);
		}
	}
}
signed main() {
	cin >> t;
	init();
	while (t--) {
		cin >> n >> m;
		if (n > m)swap(n, m);
		int ans = 0;
		for (int i = 1, j; i <= n; i = j + 1) {
			j = min(get(n, i), get(m, i));
			ans += (mu[j] - mu[i - 1]) * s[m / i] * s[n / i];
		}
		cout << ans << "\n";
	}
}

事实上,这个性质还可以推广,证明类似

d(ij)=x|iy|j[gcd(x,y)=1]

d(ijk)=x|iy|jz|k[gcd(x,y)=1][gcd(x,z)=1][gcd(y,z)=1]

一般形式:

d(i=1nai)=b1|a1bn|an[gcd(b1,b2)]()

甚至于还可以扩展到σk(n)=d|ndk(k=0)

σk(ij)=x|iy|j[gcd(i,j)=1]xk·jkyk

σk(ijk)=x|iy|jz|k[gcd(x,y)=1][gcd(x,z)=1][gcd(y,z)=1](xjykz)k

posted @   spdarkle  阅读(74)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示