提示:对于这种与gcd有关的式子别用莫比乌斯反演公式,会炸的
只需要记住:
[gcd(i,j)=1]=∑d∣gcd(i,j)μ(d)
证明?其实很简单。
∑d∣nμ(d)=[n=1]
将
d替换成
gcd(i,j)就是上面的那个暂且可以称作公式的式子了
例1
求
∑i=1n∑j=1m[gcd(i,j)=1] (n<m)
直接套公式啦
=∑i=1n∑j=1m∑d∣gcd(i,j)μ(d)
然后我们枚举
d,显然有
d∈(1,n) (d∣gcd(i,j))
于是将
d提到前面去,则
i,j都是
d的倍数,化简一下,得
=∑d=1nμ(d)∗⌊dn⌋∗⌊dm⌋
注意到后面那一坨是可以
O(n)分块做的
于是我们实现了
O(n2)到
O(n)的过渡
简单吧
例2
求
∑i=1n∑j=1m[gcd(i,j)=k] (n<m)
好像与上一题有点不一样
但我们可以转化成一样的
=∑i=1⌊kn⌋∑j=1⌊km⌋[gcd(i,j)=1]
然后就一样了
例3
求
∑i=1n∑j=1mij[gcd(i,j)=k] (n<m)
老方法,同时除以
k,只不过与上一题不同的是,我们需要考虑
i,j的贡献
=∑i=1⌊kn⌋∑j=1⌊km⌋ij[gcd(i,j)=1]∗k2
有同学可能要问了
因为在
i,j同时除以
k的同时,中间那个
ij的值就变了,
i,j同时缩小到了原来的
k1,所以最后要把缩小的乘回来,就是
k2
让我们继续套路,将中间那个
gcd(i,j)用莫比乌斯替换掉
=∑i=1⌊kn⌋∑j=1⌊km⌋ij∑d∣gcd(i,j)μ(d)∗k2
=∑d=1⌊kn⌋μ(d)∗d2∑i=1⌊kdn⌋∑j=1⌊kdm⌋ij∗k2
各归各家,各找各妈
=k2∗∑d=1⌊kn⌋μ(d)∗d2∑i=1⌊kdn⌋i∑j=1⌊kdm⌋j
我们发现,最后那两项,不就是
…等差数列吗?
时间复杂度
O(n2)→O(n)
来一个强的
例4
求
∑i=1n∑j=1mlcm(i,j)
首先,小学奥数告诉我们
lcm(i,j)=gcd(i,j)i∗j
可以看看我的另外一篇博客
莫比乌斯反演-从莫比乌斯到欧拉,里面详细地介绍了一种奇妙的反演方法,大致思路是用
ϕ函数替换
μ函数。我暂且把它叫做
欧拉反演。
但是注意,如果
gcd(i,j)出现在分母这种不正常的位置,就不能用那个神奇的欧拉反演,而应该用常规方法。
仍然是老套路,枚举
gcd(i,j)
=∑d=1n∑i=1n∑j=1mdi∗j∗[gcd(i,j)=d]
=∑d=1n∑i=1⌊dn⌋∑j=1⌊dm⌋i∗j∗d∗[gcd(i,j)=1]
=∑d=1n∑i=1⌊dn⌋∑j=1⌊dm⌋i∗j∗d∑k∣gcd(i,j)μ(k)
=∑d=1nd∑k=1⌊dn⌋μ(k)∗k2∑i=1⌊dkn⌋i∑j=1⌊dkm⌋j
这时,这已经是一个
O(n)的做法,观察可以得到,
⌊dn⌋可以分一次块,
⌊dkn⌋可以再分一次块,总时间复杂度是
O(n∗n)=O(n)
推到这里已经很牛逼了,但我们还有更好的方法,这个时间复杂度还能优化
后面那两坨等差数列很烦,我们把它换掉
设
T=dk,f(x)=∑i=1xi,把原来那个式子换成
=∑d=1nd∑k=1⌊dn⌋μ(k)∗k2∗f(⌊Tn⌋)∗f(⌊Tm⌋)
看好了,下面的步骤很奇妙
用枚举
gcd(i,j)的方法,我们枚举
T
=∑T=1nf(⌊Tn⌋)∗f(⌊Tm⌋)∑d∣Td∗μ(dT)∗(dT)2
=∑T=1nf(⌊Tn⌋)∗f(⌊Tm⌋)∑d∣Td∗μ(d)∗T
但别担心,我们观察最后这个式子
∑d∣Td∗μ(d)∗T
∑d∣Td∗μ(d)
设
F(T)=∑d∣Td∗μ(d)
F(a)=∑d∣ad∗μ(d)
F(b)=∑d∣bd∗μ(d)
显然
a,b对
F(ab)的贡献是没有交集的,而这时,在我们枚举
d时,它既可以是
a的约数,也可以是
b的约数,还能是
ab的约数。具体来说,
F(a)的某一项乘
F(b)的某一项一定等于
F(ab)的某一项(一个
a的因子与一个
b的因子相乘一定是
ab的因子)
μ(a的某个因子
k)∗μ(b的某个因子
j)=μ(k∗j)
常识告诉我们,积性函数是可以
O(n)筛的,
F也一样
有
F(a)=1−a
如果
a⊥b,则
F(a∗b)=F(a)∗F(b)
这三个公式易得出,我们考虑
a≡0 (mod b)且
b是质数的情况
则
F(a∗b)比
F(a)多出的几项中,
d分解后,项
b的次数一定大于
1
想一想,为什么
因为,如果
b这一项的次数小于等于
1,它就一定在
F(a)中被运算过了!(
a一定有
b这个质因子)
别忘了,当某个数的某个质因子次数大于
1,它的
μ值就是
0啊!
故此时
F(a∗b)=F(a)
于是,我们推导出了
F函数的转移公式,代码表示如下(顺便处理一下前缀和)
CPPvoid sieve() {
F[1]=sum[1]=1;
for (int i=2;i<=10000000;i++) {
if (!flag[i]) prime[++cnt]=i,F[i]=1-i;
for (int j=1;j<=cnt&&i*prime[j]<=10000000;j++) {
flag[i*prime[j]]=1;
if (i%prime[j]==0) {
F[i*prime[j]]=F[i];
break;
}
F[i*prime[j]]=F[i]*F[prime[j]];
}
sum[i]=sum[i-1]+F[i]*i;
}
}
回到公式
=∑T=1nf(⌊Tn⌋)∗f(⌊Tm⌋)∑d∣Td∗μ(d)∗T
我们只需要分块求前面那两个
f,后面那一坨
O(1)处理(都筛出来了)
时间复杂度
O(n)→O(n)
当你想降一下时间复杂度时,枚举第二个分块中的某一项再进行处理可能是一个好选择。
例5
求
∑i=1n∑j=1md(i∗j)
其中,
d(i∗j)表示
i∗j的约数个数
我们有一个公式
d(i∗j)=∑x∣i∑y∣j[gcd(x,y)=1]
很多人不知道这个公式是怎么推的,我来解释一下
其实,这里的
[gcd(i,j)=1]并不是为了去重,而是为了和左边的式子保持相等
我们考虑一个质数
p,
i=i′∗pk1,j=j′∗pk2,注意这里
k1,k2可以为
0
考虑
p对
d(i∗j)的贡献,显然,在
d的因子中,
p的这一项可以为
0~
k1+k2共
k1+k2+1个
考虑等式右边,我们只看
p这一项。
x=x′∗pkx,y=y′∗pky
要满足
gcd(x,y)=1,那么就有
gcd(pkx,pky)=1
要么
kx=0,ky∈[0,k2],共
k2+1种
要么
ky=0,kx∈[0,k1],共
k1+1种
减去重复判断的
kx=0,ky=0这种情况,最后答案
k1+k2+1种
与等式左边相同!
剩下的步骤都很水了,所以我把这留作练习,如果你认真阅读了以上所有内容,那么这个练习就可以轻松解决。
练习
练习1
上面说了
练习2
求
∏i=1n∏j=1mf[gcd(i,j)] (n,m≤106,T≤1000)
练习3
求
∑i=1n∑j=1mgcd(i,j)k (n,m≤5∗106,T≤2000)
后记
感谢lyc大佬的指导,在他的帮助与耐心解答下,我才初识了懵逼钨丝反演莫比乌斯反演
只要掌握方法,能够耐心地进行推导,莫比乌斯系列的题目其实不难