笔记 莫比乌斯反演

反演

反演的作用基本上就是将一个bool表达式转化成一个和式,从而减小程序的时间复杂度。

欧拉反演

基本式子是

\[n=\sum_{d|n}\phi(d) \]

下面简单证明一下,我们枚举\(n\)的每个因子\(d\),显然每个因子都有可能成为\(n\)\(1-n\)中的数的gcd,并且每个gcd都是,即\(n=\sum_{d|n}\sum_{i=1}^{n}[gcd(i,n)==d]\),其中\([gcd(i,n)==d]\)这个是一个bool表达式,当且仅当\([gcd(i,n)==d]\)时,该式子返回1,其余时候返回0。

进一步化简得到

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

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

\[n=\sum_{d|n}\phi(\frac{n}d) \]

因为在枚举约数的时候,对于一个约数\(d\),总会有一个约数\(\frac{n}d\)与之对应(可能相等),即所有的约数都是对称的,所以原式可以继续化简为

\[n=\sum_{d|n}\phi(d) \]

证毕。

有什么用呢?
来看一个十分眼熟的式子。

\(\sum_{i=1}^ngcd(i,n)\)的值。

相信一些大佬会秒算出答案,即\(\sum_{d|n}d\times\phi(\frac{n}d)\)

不如换一个角度推导,根据上述中的\(n=\sum_{d|n}\phi(d)\)来化简一下。

\[\sum_{i=1}^ngcd(i,n) \]

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

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

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

显然每个\(d\)对答案的贡献只有\(\frac{n}d\)个,好吧并不显然,举个例子,假设\(d=1\),那么\(d\)能整除这全部\(n\)个数,答案就会增加\(n\times\phi(1)\),类似的,对于每个\(d\),答案都会增加\(\frac{n}d\times\phi(d)\),所以上式化简为

\[\sum_{d|n}\frac{n}d\phi(d) \]

因为约数是对称的,所以它和上边那个一眼的式子是相等的。

虽然到这里反演仍旧没有发挥什么很大的作用,但是我们不妨继续魔改上边的式子,这次——

\(\sum_{i=1}^n\sum_{j=1}^ngcd(i,j)\)的值。这个总不能一眼看出答案吧

所以我们继续反演

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

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

\[=\sum_{i=1}^n\sum_{j=1}^n\sum_{d|i}\sum_{d|j}\phi(d) \]

直到这一步和上边的推导还是相似的,我不会告诉你我是复制的

但是我们发现它不能像上边的式子继续化简了,因为\(i,j\)都是不确定的量,如果直接枚举,时间复杂度没有任何变化,仍旧是\(O(N^2)\),思考一下\(i,j\)共同有的是什么,没错是\(d\)

于是可以枚举\(d\)

对于每个约数\(d\),它所能造成的贡献还是\(\frac{n}d\),不过由于这次没有条件\(d|n\),所以需要稍微变化一点,手模一下发现它成了\(\lfloor\frac{n}d\rfloor\),但在代码上边还是\(n/d\),上式继续化简为

\[\sum_{d=1}^n\lfloor\frac{n}d\rfloor\lfloor\frac{n}d\rfloor\phi(d) \]

但是代码里要写成这样

(n/d)*(n/d)*phi[d];

而不是

n/d*n/d*phi[d];

因为必须要先向下取整再进行运算。

也许这样还有别的奇奇怪怪的方法可以算出来,于是继续改变上述式子。

\(\sum_{i=1}^n\sum_{j=1}^mgcd(i,j)\)的值

这个莫比乌斯反演也可以做,不过好像没有必要,仍旧套上边欧拉反演的式子,得到原式为

\[\sum_{d=1}^{min(n,m)}\lfloor\frac{n}d\rfloor\lfloor\frac{m}d\rfloor\phi(d) \]

以上就是欧拉反演了,虽然有些时候用起来还可以但是大多时候有局限性,所以建议学习莫比乌斯反演

莫比乌斯反演

好了,那如果问题继续发展,改成——

\(\sum_{i=1}^n\sum_{j=1}^ngcd(i,j)==k\)的值呢?

但这样好像就没有办法使用欧拉反演了,于是我们考虑使用其它办法。

首先引入一个函数\(\mu\),它的定义为

\[\mu(x)=\left\{ \begin{array}{rcl} 1 & & {x==1}\\ (-1)^k & & {x==p_1p_2…p_k}\\ 0 & & {otherwise}\\ \end{array} \right. \]

其实这就是所谓的莫比乌斯函数,深刻理解一下它的含义,特殊的,当\(x==1\)的时候,它的值为1,否则当\(x\)中所含的单个质因子数目不超过1时,它的值为-1的质因子数目次方,其余情况为0。

假设在有两个定义在复数域上的函数\(f,g\)满足

\[f(x)=\sum_{d|x}g(d) \]

那么有

\[g(x)=\sum_{d|x}\mu(d)f(\frac{x}d) \]

至于证明,个人感觉使用Dirichlet卷积会比较好证明一点。

定义两个数论函数\(f,g\)的Dirichlet卷积为
\((f*g)(n)=\sum_{d|n}f(d)g(\frac{n}d)\)

然后再介绍一些基本的数论函数

\(\varepsilon(x)\)当且仅当\(x==1\)时返回1

\(d(x)\)返回\(x\)的约数个数

\(\sigma(x)\)返回\(x\)的约数和

\(\varphi(x)\)这个返回啥感觉可以不说

\(id(x)\)返回\(x\)

\(I(x)\)返回1

由卷积的定义可知,原问题可以化为
已知

\[f=g*I \]

求证

\[g=\mu*f \]

这里我们用一个很常用的性质,

\[\mu*I=\varepsilon \]

\[\mu*I=[n==1] \]

我们先来证明一下,

\[\mu*I=\sum_{d|n}\mu(d) \]

也就是相当于求\(n\)的因子的莫比乌斯函数值的和。

因为只有在一个数的单个质因子不超过1时,才会返回不为0的值,所以只需要考虑\(d\)中的质因子。

假设\(d\)中共含有\(k\)个质因子,那么原式可以化为

\[1-C_k^1+C_k^2-C_k^3………+(-1)^kC_k^k \]

于是你就会发现一个很神奇的东西,这个就是…二项式定理

所以

\[\mu*I=(1-1)^k \]

当且仅当\(k==0\)时,原式为1,易得此时\(n==1\)

证毕

所以,对

\[f=g*I \]

两边同时卷上\(\mu\),得到

\[\mu*f=g*I*\mu \]

然后

Dirichlet 卷积满足交换律和结合律。

证明 百度百科说的

\[\mu*f=g*(I*\mu) \]

\[g=f*\mu \]

Dirichlet 卷积还有很多性质,比如

\[\varphi=id*\mu \]

由这个可以得到什么呢?

两边同时卷上\(I\),会得到

\[\varphi*I=id*\mu*I=id*(\mu*I) \]

\[\varphi*I=id \]

把它卷出来就会发现,这不就是欧拉反演的式子吗!

那我们回到正题,求\(\sum_{i=1}^n\sum_{j=1}^ngcd(i,j)==k\)

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

\[F(d)=\sum_{d|k}f(k)=\lfloor\frac{n}d\rfloor\lfloor\frac{n}d\rfloor \]

那么反演一下,得到

\[f(k)=\sum_{d|k}\mu(\frac{k}d)F(k) \]

\[f(k)=\sum_{d|k}\mu(\frac{k}d)\lfloor\frac{n}d\rfloor\lfloor\frac{n}d\rfloor \]

\(T=\frac{k}d\)

\[f(k)=\sum_{T=1}^{\frac{n}k}\mu(T)\lfloor\frac{n}{kT}\rfloor\lfloor\frac{n}{kT}\rfloor \]

这么推导十分满足莫比乌斯反演的式子,但好像两个函数比较难设出来,所以可以采取一个强大某些时候可能推不出来的办法。

举个例子

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

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

上边我们已经证明了

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

\(gcd\)替换\(n\)得到

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

\[\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{d|i}\sum_{d|j}\mu(d) \]

换一下位置

\[\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{d|i}\sum_{j=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{d|j}\mu(d) \]

仍旧像欧拉反演那样,枚举每一个\(d\),分别计算贡献。

\[\sum_{d=1}^{\lfloor\frac{n}{k}\rfloor}\lfloor\frac{n}{kd}\rfloor\lfloor\frac{n}{kd}\rfloor\mu(d) \]

推出来的式子是一样的。

但是这样的时间复杂度可能还是\(O(n)\)的,在面临很多询问的时候仍旧会挂,于是考虑继续优化,这时候需要用到整除分块,有一部分数,他们\(\lfloor\frac{n}{kd}\rfloor\)的值是一样的,并且对于值为\(\lfloor\frac{n}{i}\rfloor\)的块,它的右端点为\(\lfloor\frac{n}{\lfloor\frac{n}{i}\rfloor}\rfloor\),我们可以先线性筛出\(\mu\)的前缀和,然后对于这些值一样的数一起计算,这样时间复杂度就是\(O(\sqrt n)\)的了。

posted @ 2020-07-19 07:08  An_Fly  阅读(151)  评论(3编辑  收藏  举报