莫比乌斯反演

1 数论分块

数论分块是莫比乌斯反演的前置知识之一,其主要用于快速求解一些含有除法向下取整的和式,例如 ni。我们的主要思路是,由于 ni 中有大量值相同,所以可以将这些值一样的部分放在一起计算。

下面先说明几个引理。

1.1 引理

引理 1:

nN+,|{nd|dN+,dn}|2n

也就是说 nd 的值的个数不超过 2n

证明:

对于 dnnd 的值最多有 n 个。

对于 d>n,则说明 ndn,因此值最多有 n 种。

这个引理保证了数论分块的复杂度是正确的 O(n)

引理 2:

n,lN+,ln,使得:

nl=nr

成立的最大的满足 lrnr 的值为 nnl

证明:

考虑设 k=nl。考虑此时对于任意一个合法的 x,都必然有 nx=k,即 n=kx+r(0r<x)

然后我们即可得到:

n=kx+rnkxxnk

所以 x 的最大值为 nk,也即 r=nnl

这个引理告诉我们对于一个块,如果其之内的值全部都是 nl,则这个块的右端点为 r=nnl


那么根据上面两个基本的引理,实际上我们就已经能求解一些简单的东西了。具体的,我们每一次求出块的左右端点,按照要求求出相应值,再转移左端点即可。

例 1: [CF1263C] Everyone is a Winner!

我们直接按照上面的思想转移区间即可,代码如下:

#include <bits/stdc++.h>

using namespace std;

const int Maxn = 2e5 + 5;
const int Inf = 2e9;

int T, n;
int tot[Maxn], cnt = 0;

void solve() {
	cin >> n;
	cnt = 0;
	int l = 1, r = 0;
	while(l <= n) {
		r = n / (n / l);
		tot[++cnt] = n / l;
		l = r + 1;
	}
	tot[++cnt] = 0;
	sort(tot + 1, tot + cnt + 1);
	cout << cnt << '\n';
	for(int i = 1; i <= cnt; i++) cout << tot[i] << " ";
	cout << '\n';
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	cin >> T;
	while(T--) solve();
	return 0;
}

引理 3:

a,b,cZ,abc=abc

证明:

ab=ab+r(0r<1)

所以有:

abc=ab×1c=(ab+r)×1c=abc+rc=abc

2 莫比乌斯反演

2.1 概念

莫比乌斯反演是数论中的重要内容,对于一些函数 f(n),如果我们不好直接求解其值,但是能快速求出其倍数和 / 约数和的话,就可以通过莫比乌斯反演来优化。

2.2 莫比乌斯函数

2.2.1 定义

定义莫比乌斯函数 μ(n) 如下:

μ(n)={1n=10n (1)kk  n 

2.2.2 性质

莫比乌斯函数的性质较多,有如下几条。

性质 1: μ(n) 是积性函数。

这意味着 μ(n) 可以利用欧拉筛直接求解。

性质 2:

dnμ(d)={1n=10n=0

证明:

考虑设 n=i=1kpici,n=i=1kpi

dnμ(d)=dnμ(d)=i=0k(ki)(1)i=i=0k(ki)(1)i1ki

由二项式定理易知上式值为 (1+(1))k。此时我们只有取 k=0n=1 时原式值为 1

性质 3:

[gcd(i,j)=1]=dgcd(i,j)μ(d)

证明:

其实就是性质 2 的一个推论,但是在题目中会经常见到 gcd(i,j)=1 的形式,需要想到这一步变换。

2.2.3 线性筛求解

上文提到过 μ(n) 是一个积性函数,所以直接线性筛求解即可。

代码如下:

int prim[Maxn], cnt, mu[Maxn];
bool vis[Maxn];
void init(int N) {
	mu[1] = 1;
	for(int i = 2; i <= N; i++) {
		if(!vis[i]) {
			prim[++cnt] = i;
			mu[i] = -1;
		}
		for(int j = 1; j <= cnt && prim[j] * i <= N; j++) {
			vis[prim[j] * i] = 1;
			if(i % prim[j] == 0) {
				mu[prim[j] * i] = 0;
				break;
			}
			mu[prim[j] * i] = -mu[i];
		}
	}
}

2.3 莫比乌斯变换

f(n),g(n) 为两个数论函数。如果有:

f(n)=dng(d)

那么有:

g(n)=dnμ(d)f(nd)

我们称这种形式下的 f(n)g(n) 的莫比乌斯变换,而 g(n) 称为 f(n) 的莫比乌斯逆变换,即莫比乌斯反演。

考虑如何证明,我们对原式进行如下变换即可:

dnμ(d)f(nd)=dnμ(d)kndg(k)=kng(k)dnkμ(d)=kng(k)[nk=1]=g(n)

当然莫比乌斯反演还有第二种形式,即倍数的形式:

如果有:

f(n)=ndg(d)

那么有:

g(n)=ndμ(dn)f(d)

那么以上就是莫比乌斯反演的基础内容,下面我们来看题目中的实际运用。

3 例题

莫比乌斯反演可以处理一类求和式,形如:

i=1nj=1mf(gcd(i,j))

下面举三例讲解如何操作这类求和式。

例 2:YY的GCD

题意:i=1nj=1m[gcd(i,j)P],其中 P 为全体质数构成的集合。

不妨先令 n<m,然后对该式子进行如下变换:

i=1nj=1m[gcd(i,j)P]=i=1nj=1mpP[gcd(ip,jp)=1]=pPi=1npj=1mp[gcd(i,j)=1]=pPi=1npj=1mpdgcd(i,j)μ(d)=pPi=1npj=1mpd=1np[di][dj]μ(d)=pPd=1npμ(d)i=1np[di]j=1mp[dj]=pPd=1npμ(d)npdmpd

发现分母是两个变量,难以数论分块求解。考虑设 T=pd,则有:

pPd=1npμ(d)npdmpd=pPT=1npμ(Tp)nTmT=T=1nnTmTpPpTμ(Tp)

f(T)=pPpTμ(Tp),则原式即为:

T=1nf(T)nTmT

预处理出 f(T) 前缀和然后数论分块求解即可。

例 3: [SDOI2014] 数表

题意:σ(n) 表示 n 的约数和。即求:

i=1nj=1mσ(gcd(i,j))[σ(gcd(i,j))a]

依然假设 n<m,我们做如下变换:

i=1nj=1mσ(gcd(i,j))[σ(gcd(i,j))a]=d=1nσ(d)[σ(d)a]i=1nj=1m[gcd(i,j)=d]

后面的和式处理仿照上一题显然可得:

=d=1nσ(d)[σ(d)a]k=1nμ(k)ndkmdk

仍然令 T=dk,可得:

=T=1nd=1dTnσ(d)[σ(d)a]μ(Td)nTmT=T=1nnTmTd=1dTnσ(d)[σ(d)a]μ(Td)

F(T)=d=1dTnσ(d)[σ(d)a]μ(Td),则:

=T=1nF(T)nTmT

到这里和上一题是一样的,难点在于 F(T) 中的 [σ(d)a]。我们考虑线性筛时预处理出 σ(d),然后将 σ(d) 排序,并且将询问离线下来也按 a 排序。这样我们就可以边回答询问边往 F(T) 里加入贡献。

然后会发现此时我们不能单次去处理前缀和,不然复杂度会爆炸,接着不难想到利用树状数组进行单点修改、区间查询,最后数论分块求解即可。

例 4:[SDOI2015] 约数个数和

题意:设 d(x) 表示 x 的约数个数,求 i=1nj=1md(ij)

首先需要了解 d 函数的一个重要性质:

d(ij)=xiyj[gcd(x,y)=1]

证明如下:

考虑两者相乘后的约数的因子,对其进行质因数分解。假如其中有一项是 pa,并且这个质数在 i,j 的分解式中分别表现为 pb,pc。我们钦定先从 i 中选,因此:

  • ab,我们认为该因子所有的 p 都来自于 i,此时 i,j 选出的数在这一项上互质。
  • a>b,则我们会先选 i 中的 pb,然后选 j 中的 pab。我们可以认为,当我们从 j 中选 p 这个质数的时候,i 一定是选满了的。所以我们可以认为,当 j 选了这个质数而 i 没有选时,其实是 i 已经选满了。这样也能保证不漏情况。发现此时 i,j 选出的数在这一项上同样互质。

综上,对于每一项,i,j 选出的数都是互质的。因此最后的总方案数就是二者互质的方案数。

然后原式可以化为:

i=1nj=1mxiyj[gcd(x,y)=1]=i=1nj=1mxiyjdgcd(x,y)μ(d)=i=1nj=1mdgcd(i,j)μ(d)xi[dx]yj[dy]

考虑后面的两个和式,设 x=kd,则求和的要求就是 kdi,由于 dgcd(i,j),所以只需满足 kid 即可,因此后面的和式其实就是 d(id)。所以有:

=i=1nj=1mdgcd(i,j)μ(d)d(id)d(jd)=d=1nμ(d)i=1n[di]d(id)j=1n[dj]d(jd)=d=1nμ(d)i=1ndd(i)j=1mdd(j)

F(n)=i=1nd(i),则有:

=d=1nμ(d)F(nd)F(md)

预处理出 d(i),F(i) 后数论分块求解即可。

posted @   UKE_Automation  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示