莫比乌斯反演学习笔记

【前言】

运用莫比乌斯反演通常可以将复杂的求和柿子简单化。

除特殊说明,约定所有除法均为整除。

【前置芝士】

【整除分块】

\(N/i′=N/i\) 相等,则 \(i′\) 的最大值为 \(N/(N/i)\)

证明:

必要性\(\left\lfloor\dfrac{N}{i'}\right\rfloor\)\(\left\lfloor\dfrac{N}{i}\right\rfloor\) 相等,也就是 \(\left\lfloor\dfrac{N}{i'}\right\rfloor=\left\lfloor\dfrac{N}{i}\right\rfloor\),得到 \(\dfrac{N}{i'}≥\left\lfloor\dfrac{N}{i}\right\rfloor\)

两边取倒数,不等号变向 \(\dfrac{i'}{N}≤1/(\left\lfloor\dfrac{N}{i}\right\rfloor)\)

两边同乘 \(N\),得到 \(i'≤N/(\left\lfloor\dfrac{N}{i}\right\rfloor)\)

也就是 \(i'≤\left\lfloor\dfrac{N}{\left\lfloor\dfrac{N}{i}\right\rfloor}\right\rfloor\)

充分性=:令 \(i'=\left\lfloor\dfrac{N}{\left\lfloor\dfrac{N}{i}\right\rfloor}\right\rfloor\)

得到 \(\left\lfloor\dfrac{N}{i'}\right\rfloor=\left\lfloor\dfrac{N}{\left\lfloor\dfrac{N}{\left\lfloor\dfrac{N}{i}\right\rfloor}\right\rfloor}\right\rfloor=\left\lfloor\dfrac{N}{i}\right\rfloor\)

证毕。

也就是说我们知道了一个区间的左端后,令 \(r=\left\lfloor\dfrac{N}{\left\lfloor\dfrac{N}{l}\right\rfloor}\right\rfloor\) 整个区间 \([l,r]\)\(\left\lfloor\dfrac{N}{i}\right\rfloor\) 的值是一样的。

然后就可以愉快的 \(O(\sqrt N)\) 分块了。

【狄利克雷卷积与数论函数】

【基本符号】

两个函数 \(f(n),g(n)\) 的狄利克雷卷积写作 \(f*g\)

定义:\(f*g=\sum\limits_{d|n} f(d)g(n/d)\)

它满足以下显然的运算律:

  1. \(f*g=g*f\)
  2. \((f*g)*h=f*(g*h)\)
  3. \((f+g)*h=f*h+g*h\)

然后是在卷积中常用到的几个数论函数:

  1. \(I(n)\)恒等函数,无论 \(n\) 为何值,\(I(n)=1\)
  2. \(\varepsilon(n)\)元函数,是卷积中的单位元,当 \(n=1\) 时,\(\varepsilon(n)=1\),否则为 \(0\)
  3. \(id(n)\)单位函数\(id(n)=n\)
  4. \(\varphi(n)\)欧拉函数,小于等于 \(n\) 的整数中,与 \(n\) 互质的数的个数。
  5. \(\mu(n)\)莫比乌斯函数,定义见后。

其中 \(1\sim3\) 都是完全积性函数,\(4,5\) 是积性函数。

定理:两个积性函数的狄利克雷卷积还是积性函数。

\(\varepsilon=f*g\) 时,我们称 \(f,g\) 互逆。

【数论函数】

这里给出更加全面的数论函数的介绍。

常用数论函数表:

函数名称 符号 定义 积性 卷积
恒等函数 \(I(n)\) 永远等于 \(1\) 完全积性函数
元函数 \(\varepsilon(n)\) \(n=1\) 时,\(\varepsilon(n)=1\),否则为 \(0\) 完全积性函数
单位函数 \(id(n)\) 函数值为 \(n\) 完全积性函数
幂函数 \(id^x(n)\) 函数值为 \(n^x\) 完全积性函数
莫比乌斯函数 \(\mu(n)\) \(\mu * I = e\) 积性函数 \(\mu*I=e\)
欧拉函数 \(\varphi(n)\) 小于等于 \(n\) 的整数中,与 \(n\) 互质的数的个数 积性函数 \(\varphi*I=id\)
约数个数函数 \(d(n)\),也作 \(\sigma_0(n)\) \(n\) 的约数个数 积性函数 \(I*I=d\)
约数和函数 \(\sigma(n)\) \(n\) 的约数和 积性函数 \(I*id=\sigma\)
除数函数 \(\sigma_k(n)\) \(n\) 的约数 \(k\) 次方和 积性函数 \(I*id^k=\sigma_k\)

欧拉函数 \(\varphi(n)=\sum\limits_{i=1}^n [\gcd(i,n)=1]\)

它是积性函数,可以使用线性筛求出。

简单代码:

phi[1] = 1;
if(i is a prime) phi[i] = i - 1;
// now, we get a prime named p,and a number i
if(i % p) phi[i * p] = phi[i] * (p - 1);
else {phi[i * p] = phi[i] * p; break;}

不仅如此,约束函数也是可以线性筛的。

公式挺好推的,例如 \(\sigma(n)\)。(顺便带上一个 \(\mu(n)\)

int num = i * prm[j];
if(i % prm[j])
    mu[num] = - mu[i], sum[num] = sum[i] * (prm[j] + 1);
else{
    mu[num] = 0;
    sum[num] = (prm[j] + 1) * sum[i] - prm[j] * sum[i / prm[j]];
    break;
}

【卷积结论】

\[id=I*\varphi \]

即:\(\sum_{d\mid n}\varphi(d)=n\)

证明一下,设 \(F=I*\varphi\),因为 \(F\) 为积性函数,所以只需证明对于所有 \(F(prime^k)=prime\) 即可。

\[\sum\limits_{d\mid p^k}\varphi(d) \]

\[=\varphi(1)+\varphi(p)+\varphi(p^2)+\cdots+\varphi(p^k) \]

\[=1+(p-1)+p(p-1)+p^2(p-1)+\cdots+p^{k-1}(p-1) \]

\[=1+(p-1)(1+p+\cdots+p^{k-1}) \]

\[=1+(p-1)\frac{p^k-1}{p-1} \]

\[=p^k \]

Q.E.D

我们还可以得到一下结论:\(I*\varphi =id\to \mu * id = \varphi\)

即:\(\sum_{d\mid n}\mu(d)(n/d)=\varphi(n)\)

这只是众多反演结论中的一个,但已经有力地证明了卷积的强大作用。

【反演公式】

\(F(n)=\sum\limits_{d|n} f(d)\)

显然 \(F(n)=\sum\limits_{d|n} 1\times f(d)\)

写成卷积的形式 \(F=I*f\)

如果 \(f\) 很容易求,那么可以直接根据定义推得 \(F\)

但如果 \(F\) 易求而需要反推 \(f\),就两边同时乘 \(I^{-1}\) 得:

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

也就是说,只需要构造一个函数与 \(I\) 互逆,那么用其卷积就可以简单得到答案。

于是我们构造了 \(\mu * I=\varepsilon\),也就是莫比乌斯函数。

然后就有了反演公式:

  • 嵌入式反演公式:最基本的公式。

    \(\mu *I=\varepsilon\)\(\sum\limits_{d|n}\mu(d)=[n=1]\)

  • 约数式反演公式

    若有:

    \[F(n)=\sum\limits_{d|n} f(d) \]

    则:

    \[f(n)=\sum\limits_{d|n} \mu(d)F(n/d) \]

    也作:

    \[f(n)=\sum\limits_{d|n} \mu(n/d)F(d) \]

    简单证明:\(F=f*I\to f=F*I^{-1}\to f=F*\mu\)

  • 倍数式反演公式

    若有:

    \[F(n)=\sum\limits_{n|d} f(d) \]

    则:

    \[f(n)=\sum\limits_{n|d} \mu(d/n)F(d) \]

    这个不是卷积形式,需要证明一下。

    \(F(n)\) 的定义代入得:

    \[=\sum\limits_{n|d}\mu(d/n)\sum\limits_{d|t} f(t) \]

    考虑枚举 \(d=kn\)

    \[=\sum\limits_{k}\mu(k)\sum\limits_{nk|t} f(t) \]

    交换求和符号得:

    \[=\sum\limits_{t}f(t)\sum\limits_{nk|t}\mu(k) \]

    \[=\sum\limits_{t}f(t) \sum\limits_{n|t,k|(t/n)} \]

    根据嵌入式反演公式得:

    \[=\sum\limits_{t}f(t)[t=n]=f(n) \]

    证毕。

【简单应用】

首先提示,本文中默认 \(n\leq m\)

练手题:

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

直接用反演公式:

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

交换求和顺序得:

\[=\sum\limits_{d=1}^n \mu(d) \sum\limits_{d|i}^n \sum\limits_{d|j}^m 1 \]

\[=\sum\limits_{d=1}^n \mu(d)\lfloor n/d\rfloor\lfloor m/d\rfloor \]

运用整除分块 + 预处理 \(\mu\) 的前缀和可以 \(O(n+\sqrt n)\) 解决。

GCD

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

首先这题可以用 \(\varphi(n)\) 直接上。

\[Ans=\sum\limits_{p\in prime} \varphi(n/p)\times 2 \]

但是没有反演魔术,很没有做题体验。

考虑针对每个质数单独处理,因为质数分布为 \(\log\log n\) 的,所以不用担心复杂度。

然后针对质数 \(p\),我们需要统计:

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

考虑枚举 \(i,j\) 分别为 \(p\) 的几倍:

\[=\sum\limits_{i=1}^{\lfloor n/p\rfloor}\sum\limits_{j=1}^{\lfloor m/p\rfloor}[\gcd(i\times p,j\times p)=p] \]

\[=\sum\limits_{i=1}^{\lfloor n/p\rfloor}\sum\limits_{j=1}^{\lfloor m/p\rfloor}[\gcd(i,j)=1] \]

然后就是和上面一样的问题了。

YY的GCD

和上一题一样,有 \(T\leq 10^4\) 组数据,\(n\leq 10^7\)

枚举质数的方法跑步过去了,\(\varphi\)native 做法也不太行。

将上一步最后的柿子整理得:

\[=\sum\limits_{p\in prime}\sum\limits_{d=1}^{\lfloor n/p\rfloor} \mu(d)\lfloor n/dp\rfloor\lfloor m/dp\rfloor \]

\(T=dp\),并交换求和顺序:

\[=\sum\limits_{d=1}^n \sum\limits_{p\in prime,p|n}\mu(T/p)\lfloor n/T\rfloor\lfloor m/T\rfloor \]

再换一下顺序:

\[\sum\limits_{T=1}^n \lfloor n/T\rfloor\lfloor m/T\rfloor\sum\limits_{p\in prime,p|n}\mu(T/p) \]

前面整除分块,后面预处理,时间变为 \(O(n+T\sqrt n)\)

约数个数和

\(\sum\limits_{i=1}^n \sum\limits_{j=1}^m d(ij)\)

这题有一个很难想的点:

\[d(ij)=\sum\limits_{x\mid i}\sum\limits_{y\mid j} [\gcd(x,y)=1] \]

将每个质因子分开考虑,设 \(x=p^a\times x',y=p^b\times y'\)

那么显然:\(xy=p^a\times p^b\times x'y'\)

在等式左边,我们选择 \(p\) 的指数有 \(a+b+1\) 种选择,分别为 \(p^0,p^1,\cdots,p^{a+b}\)

在等式右边,我们同样有 \(a+b+1\) 种选择,因为 \(x,y\) 互质,所以为从 \(x\) 中选 \(1\sim a\) 个或从 \(y\) 中选 \(1\sim b\) 个,或都不选。

所以两边形成了一一映射,故等价。

然后就是快乐反演时间:

\[=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{x\mid i}\sum\limits_{y\mid j}[\gcd(x,y)=1] \]

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

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

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

\[=\sum\limits_{d=1}^n \mu(d)\sum\limits_{i=1}^{\lfloor n/d\rfloor} \sum\limits_{j=1}^{\lfloor m/d\rfloor} \lfloor n/id\rfloor\lfloor m/jd\rfloor \]

\[=\sum\limits_{d=1}^n \mu(d)\sum\limits_{i=1}^{\lfloor n/d\rfloor} \lfloor n/id\rfloor\sum\limits_{j=1}^{\lfloor m/d\rfloor} \lfloor m/jd\rfloor \]

\(g(x)=\sum_{i=1}^{x} \lfloor x/i\rfloor\)

\[=\sum\limits_{d=1}^n \mu(d)g(\lfloor n/d\rfloor)g(\lfloor m/d\rfloor) \]

显然 \(g\) 可以 \(O(n\sqrt n)\) 整除分块预处理出来,查询也可以 \(O(T\sqrt n)\) 整除分块出来。

数表

求:\(\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sigma_1(\gcd(i,j))[\sigma_1(\gcd(i,j))\leq a]\)

先反演一下:

\[=\sum\limits_{d=1}^n\sum\limits_{i=1}^{\lfloor n/d\rfloor}\sum\limits_{j=1}^{\lfloor m/d\rfloor}\sigma_1(d)[\gcd(i,j)=1] \]

\[=\sum\limits_{d=1}^n \sigma_1(d)\sum\limits_{i=1}^{\lfloor n/d\rfloor}\sum\limits_{j=1}^{\lfloor m/d\rfloor}[\gcd(i,j)=1] \]

或许可以稍微快一点:

\[=\sum\limits_{d=1}^n \sigma_1(d)\sum\limits_{i=1}^{\lfloor n/d\rfloor}\mu(i)\lfloor n/id\rfloor\lfloor m/id\rfloor \]

\[=\sum\limits_{d=1}^n \sigma_1(d)\sum\limits_{T=1}^{n}\mu(T/d)\lfloor n/T\rfloor\lfloor m/T\rfloor \]

\[=\sum\limits_{T=1}^n \lfloor n/T\rfloor\lfloor m/T\rfloor\sum\limits_{d\mid T}\sigma_1(d)\mu(T/d) \]

\(g(T)=\sum_{d\mid T}\sigma_1(d)\mu(T/d)\)

没有上述限制的话,预处理一下就没了。

考虑到每次 \(\sigma_1(d)\leq a\) 才能有作用,我们考虑将查询离线,按照 \(a\) 升序。

每次将能够记录的值插入到某个数据结构中去。

这个数据结构需要支持:插入、查询区间和,且效率至少为 \(O(\sqrt n)\),显然树状数组即可。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define MP make_pair
#define X first
#define Y second
using namespace std;

const int MX = 1e5;
const int N = 1e5 + 10;
const int M = 2e4 + 10;
int Q, tot, mu[N], sum[N], prm[N], c[N], ans[M];
bool vis[N];
struct Query{int n, m, a, id;} q[M];
pair<int, int> f[N];

int read(){
	int x = 0, f = 1; char c = getchar();
	while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
	return x * f;
}

bool cmp(Query x, Query y){return x.a < y.a;}

void Pre_Work(){
	mu[1] = 1, sum[1] = 1;
	for(int i = 2; i <= MX; i ++){
		if(!vis[i])
			prm[++ tot] = i, mu[i] = -1, sum[i] = i + 1;
		for(int j = 1, num; j <= tot && (num = i * prm[j]) <= MX; j ++){
			vis[num] = true;
			if(i % prm[j])
				mu[num] = - mu[i], sum[num] = sum[i] * (prm[j] + 1);
			else{
				mu[num] = 0;
				sum[num] = (prm[j] + 1) * sum[i] - prm[j] * sum[i / prm[j]];
				break;
			}
		}
	}
	for(int i = 1; i <= MX; i ++) f[i] = MP(sum[i], i);
	sort(f + 1, f + MX + 1);
}

int Modify(int x, int v){for(; x <= MX; x += x & -x) c[x] += v;}
int Ask(int x){int v = 0; for(; x; x -= x & -x) v += c[x]; return v;}

int Solve(int n, int m){
	if(n > m) swap(n, m);
	int sum = 0;
	for(int l = 1, r; l <= n; l = r + 1){
		r = min(n / (n / l), m / (m / l));
		sum += (Ask(r) - Ask(l - 1)) * (n / l) * (m / l);
	}
	return sum;
}

int main(){
	Q = read();
	for(int i = 1; i <= Q; i ++){
		int n = read(), m = read(), a = read();
		q[i] = (Query){n, m, a, i};
	}
	sort(q + 1, q + Q + 1, cmp);
	Pre_Work();
	int j = 1;
	for(int i = 1; i <= Q; i ++){
		while(j <= MX && f[j].X <= q[i].a){
			int d = f[j].Y;
			for(int T = d; T <= MX; T += d)
				Modify(T, mu[T / d] * sum[d]);
			j ++;
		}
		ans[q[i].id] = Solve(q[i].n, q[i].m) & ((1LL << 31) - 1);
	}
	for(int i = 1; i <= Q; i ++) printf("%d\n", ans[i]);
	return 0;
}

【总结】

莫比乌斯反演,本质是利用莫比乌斯函数与其他函数间卷积关系,对函数做一系列简化,从而更高效的解决问题。

或许在学习之后可以看看和式的相关介绍,再看文中的某些 \(\sum\) 之间的转换就很自然了。

参考资料&特别鸣谢:

  1. 莫比乌斯反演与数论函数 - command_block
  2. 莫比乌斯反演 - OI Wiki

完结撒花

posted @ 2021-06-11 08:48  LPF'sBlog  阅读(74)  评论(0编辑  收藏  举报