本人菜鸡,第一次写莫比乌斯的东西,如果有错误的话,还请各位大大指出,顺便轻喷···
首先介绍莫比乌斯反演:
观察图片里这个函数关系,我们现在有函数F与f
用公式来描述就是
其中d是x的所有因子
现在想一下,怎么用F来把f表示出来
不难得到
写成公式表示就是
那么问题来了,u是什么?答:大名鼎鼎的莫比乌斯函数
也就是求出莫比乌斯函数之后,我们就可以通过这个公式和F函数的值,求出f。主要意义就是这样做可以减少运算量。毕竟有的时候我们要求的f(x)可能很难算,或者复杂度太高。能通过求出来可以轻松得到的F,然后推导f(x)是十分划算的。
那么,我们先来了解一下莫比乌斯函数
求法也十分简单,莫比乌斯函数是积性函数,满足
而我们以前所学的线性欧拉筛,也满足这个,也就是说,我们可以直接用线性欧拉筛来预处理莫比乌斯函数,这个板子也很好找。相对的,所有积性函数,都可以用欧拉筛预处理。
那么,开始正题:反演
莫比乌斯反演一共有两种形式:
1.约数形式:
2.倍数形式:(做题更常用)
到这里为止都不难,莫比乌斯的题目的主要问题是构造,你得知道F设置成什么比较好,因为要快速求出f,就必须要求F能够快速求出。第二个问题才是公式的推导。数学真的容易杀人
在当前题目
n个数,求出其中任意m个数的所有m元公质数,如果我们能够求出在给定的n个数字中,每个数字x有多少数字与其互质,不妨记为res[x],那么,只有我们从res[x]中取出m个数字,x必然是这m个数字的m元公质数,其对答案的贡献就是result+=x;那么考虑对数,首先是x可能有多个然后是取出m个数字,是一个组合数,也就是我们的result可以写成C(res[x],m) * x * cnt[x]的形式,然后枚举每一个x就好。
现在的难点就是怎么求出rex[x],即,对于每一个数字x,有多少个数字与其互质。
转化为数学公式
其中x就是我们要当前枚举的数字,公式计算的过程中是一个常数。我们要求的就是f(1)
和平时不同的是,这里直接求f(1)我不会,我只会板子推法,从概括到一般。我们先求出f(k),然后带入k=1;
重点
我们令F(k)为,a[i]与x的最大公约数是k的倍数的个数,即gcd=k,2k,3k…,我们把这个gcd值设为d
要知道F可以在nlog(n)全部预处理结束
因为F(k)就等于所有数字里,大小是k的整数倍的数字的个数。
我们用桶的方式来记录每一个数字,那么直接for循环,从k到max,k+=k,然后F+=cnt[k]即可,再加上外层枚举k,二层循环,循环次数是max+max/2+max/3+max/4······,化成函数积分后,结果收敛为max*log(max),复杂度可以接受。(F的处理如下图所示)
然后就是一个标准的倍数形式的莫比乌斯反演:
枚举k的整数倍d,上限为能取到的最大值。
k=1带入
F(d)预处理过,可以直接带入
上代码:
#include <iostream>
using namespace std;
typedef long long LL;
const int mod=998244353;
const int N=1e5+10;
int mo[N],f[N],prime[N]