莫比乌斯函数
对于一个正整数 n n n, μ ( n ) \mu(n) μ(n)为其莫比乌斯函数。
莫比乌斯函数是怎么样定义的呢?
首先,对于任意一个正整数 n n n来说,由算数基本定理知,一定可以将其分解成 n = p 1 a 1 p 2 a 2 . . . p k a k n=p_1^{a_1}p_2^{a_2}...p_k^{a_k} n=p1a1p2a2...pkak的形式。
定义 μ ( n ) = { ( − 1 ) k , a 1 = a 2 = . . . = a k = 1 0 , o t h e r w i s e \mu(n)=\begin{cases} (-1)^k,\ a_1=a_2=...=a_k=1 \\ 0,\ otherwise \end{cases} μ(n)={(−1)k, a1=a2=...=ak=10, otherwise
关于莫比乌斯函数和的一个定理:
∑ d ∣ n μ ( d ) = { 1 , n = 1 0 , n > 1 , ( d 是 n 的 所 有 约 数 ) \sum_{d|n}\mu(d)=\begin{cases} 1,\ n=1\\0,\ n>1 \end{cases}\ ,(d是n的所有约数) d∣n∑μ(d)={1, n=10, n>1 ,(d是n的所有约数)
证明:
-
当 n = 1 n=1 n=1时,显然有 μ ( 1 ) = 1 \mu(1)=1 μ(1)=1。
-
当 n > 1 n>1 n>1时,将 n n n分解成 n = p 1 a 1 p 2 a 2 . . . p k a k n=p_1^{a_1}p_2^{a_2}...p_k^{a_k} n=p1a1p2a2...pkak,那么 n n n的约数 d d d一定是这种形式 d = p 1 b 1 p 2 b 2 . . . p k b k , ( 0 < = b i < = a i ) d=p_1^{b_1}p_2^{b_2}...p_k^{b_k}\ ,\ (0<=b_i<=a_i) d=p1b1p2b2...pkbk , (0<=bi<=ai)。
由莫比乌斯函数的定义知道,当其中某一个质数的次方 b i > 1 b_i>1 bi>1,那么它的莫比乌斯函数 μ = 0 \mu=0 μ=0,对答案没有贡献,所以我们不考虑 b i b_i bi大于 1 1 1的情况,于是乎, b i b_i bi的取值要么是 0 0 0,要么是 1 1 1。
当这 k k k个 b i b_i bi中有奇数个取 1 1 1,那么它的 μ = − 1 \mu=-1 μ=−1,偶数个 1 1 1, μ = 1 \mu=1 μ=1。
于是, ∑ d ∣ n μ ( d ) = C k 0 μ ( d 0 ) + C k 1 μ ( d 1 ) + . . . + C k k μ ( d k ) = C k 0 − C k 1 + C k 2 − C k 3 + . . . . \sum_{d|n}\mu(d)=C_k^0\mu(d_0)+C_k^1\mu(d_1)+...+C_k^k\mu(d_k) \\ =C_k^0-C_k^1+C_k^2-C_k^3+.... d∣n∑μ(d)=Ck0μ(d0)+Ck1μ(d1)+...+Ckkμ(dk)=Ck0−Ck1+Ck2−Ck3+....
由二项式定理, ( a + b ) k = C k 0 a 0 b k + C k 1 a 1 b k − 1 + C k 2 a 2 b k − 2 + . . . + C k k a k b 0 (a+b)^k=C_k^0a^0b^k+C_k^1a^1b^{k-1}+C_k^2a^2b^{k-2}+...+C_k^ka^kb^0 (a+b)k=Ck0a0bk+Ck1a1bk−1+Ck2a2bk−2+...+Ckkakb0。
代入 a = 1 , b = − 1 a=1,b=-1 a=1,b=−1,有:
( 1 − 1 ) k = C k 0 − C k 1 + C k 2 − C k 3 + . . . . = 0 (1-1)^k=C_k^0-C_k^1+C_k^2-C_k^3+....=0 (1−1)k=Ck0−Ck1+Ck2−Ck3+....=0。
于是得到, ∑ d ∣ n μ ( d ) = 0 \sum_{d|n}\mu(d)=0 d∣n∑μ(d)=0
先写这么多吧。。。好难
莫比乌斯反演
莫比乌斯反演有两种形式。
- 第一种
若 F ( n ) = ∑ d ∣ n f ( d ) , 则 f ( n ) = ∑ d ∣ n μ ( d ) F ( n d ) , ( d 是 n 的 所 有 约 数 ) 若F(n)=\sum_{d|n}f(d),则f(n)=\sum_{d|n}\mu(d)F(\frac{n}{d})\ ,\ _{(d是n的所有约数)} 若F(n)=d∣n∑f(d),则f(n)=d∣n∑μ(d)F(dn) , (d是n的所有约数)
证明:
f ( n ) = ∑ d ∣ n μ ( d ) F ( n d ) f(n)=\sum_{d|n}\mu(d)F(\frac{n}{d}) f(n)=∑d∣nμ(d)F(dn)
= ∑ d ∣ n μ ( d ) ∑ k ∣ n d f ( k ) − − − > 将 F 按 定 义 替 换 , 其 中 k 是 n d 的 所 有 约 数 =\sum_{d|n}\mu(d)\sum_{k|\frac{n}{d}}f(k)--->_{将F按定义替换,其中k是\frac{n}{d}的所有约数} =∑d∣nμ(d)∑k∣dnf(k)−−−>将F按定义替换,其中k是dn的所有约数
= ∑ k ∣ n f ( k ) ∑ d ∣ n k μ ( d ) − − − > 交 换 μ 和 f 的 枚 举 顺 序 =\sum_{k|n}f(k)\sum_{d|\frac{n}{k}}\mu(d)--->_{交换\mu和f的枚举顺序} =∑k∣nf(k)∑d∣knμ(d)−−−>交换μ和f的枚举顺序
这里为什么可以这样交换呢?
首先,我们之前是先枚举
d
d
d,然后枚举
k
k
k,满足
d
∣
n
d|n
d∣n且
k
∣
n
d
k|\frac{n}{d}
k∣dn。
如果我们先枚举
k
k
k,那么我们先要找到
k
k
k所有可能的取值从而再去枚举,从上面的关系可以看出,
k
k
k是
n
d
\frac{n}{d}
dn的所有约数,当
d
=
1
d=1
d=1的时候,
k
k
k此时的所有取值就是
k
k
k的所有取值,因为所有
n
d
\frac{n}{d}
dn的约数一定都是
n
n
n的约数。
所以,第一个 ∑ \sum ∑的条件就是 k ∣ n k|n k∣n,来枚举 k k k所有可能的取值,那么接下来就是所有能以该 k k k配对的 d d d,使得它们仍然满足最上面的两个条件: d ∣ n d|n d∣n且 k ∣ n d k|\frac{n}{d} k∣dn,我们可以对第二个条件变形,有 k ∣ n d → k d ∣ n → d ∣ n k k|\frac{n}{d}\to kd|n\to d|\frac{n}{k} k∣dn→kd∣n→d∣kn,所以,第二个 ∑ \sum ∑的条件就是 d ∣ n k d|\frac{n}{k} d∣kn(用来枚举所有与当前 k k k配对的 d d d)。
继续我们的证明
f ( n ) = ∑ k ∣ n f ( k ) ∑ d ∣ n k μ ( d ) f(n)=\sum_{k|n}f(k)\sum_{d|\frac{n}{k}}\mu(d) f(n)=∑k∣nf(k)∑d∣knμ(d)
当我们写到这里的时候,我们发现第二维的求和正好对应了上面我们证明的莫比乌斯函数和的定理。
该定理告诉了我们,只有当
∑
d
∣
n
μ
(
d
)
\sum_{d|n}\mu(d)
∑d∣nμ(d)中的
n
=
1
n=1
n=1的时候,这个和为
1
1
1,其余情况全都等于
0
0
0。
所以我们只看 n k = 1 \frac{n}{k}=1 kn=1,也就是 k = n k=n k=n的情况,当 k = n k=n k=n的时候有:
∑ k ∣ n f ( k ) ∑ d ∣ n k μ ( d ) \sum_{k|n}f(k)\sum_{d|\frac{n}{k}}\mu(d) ∑k∣nf(k)∑d∣knμ(d)
= ∑ 1 f ( n ) ∗ 1 =\sum_1f(n)*1 =∑1f(n)∗1
= f ( n ) =f(n) =f(n)。
而当 n k ≠ 1 \frac{n}{k}\neq1 kn=1,也就是大于 1 1 1的时候,由于第二个求和的结果是 0 0 0,整个式子乘上 0 0 0结果也是 0 0 0。
所以证明出来了 ∑ k ∣ n f ( k ) ∑ d ∣ n k μ ( d ) = f ( n ) + 0 = f ( n ) \sum_{k|n}f(k)\sum_{d|\frac{n}{k}}\mu(d)=f(n)+0=f(n) ∑k∣nf(k)∑d∣knμ(d)=f(n)+0=f(n)
至此,莫比乌斯反演的第一种形式得证。
再来看莫比乌斯反演的第二种形式
- 第二种
若 F ( n ) = ∑ n ∣ d f ( d ) , 则 f ( n ) = ∑ n ∣ d μ ( d n ) F ( d ) , ( d 是 n 的 所 有 倍 数 ) 若F(n)=\sum_{n|d}f(d),则f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d)\ ,\ _{(d是n的所有倍数)} 若F(n)=n∣d∑f(d),则f(n)=n∣d∑μ(nd)F(d) , (d是n的所有倍数)
证明:
f ( n ) = ∑ n ∣ d μ ( d n ) F ( d ) f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d) f(n)=∑n∣dμ(nd)F(d)
先设 k = d n k=\frac{d}{n} k=nd,则 d = n k d=nk d=nk,那么式子可以写成
= ∑ n ∣ n k μ ( k ) F ( n k ) =\sum_{n|nk}\mu(k)F(nk) =∑n∣nkμ(k)F(nk)
= ∑ k = 1 + ∞ μ ( k ) F ( n k ) − − − > 化 简 一 下 , 约 掉 n , 因 为 是 枚 举 的 n 的 所 有 倍 数 , 是 有 无 穷 多 的 , k 上 限 是 + ∞ =\sum_{k=1}^{+\infty}\mu(k)F(nk)--->_{化简一下,约掉n,因为是枚举的n的所有倍数,是有无穷多的,k上限是+\infty} =∑k=1+∞μ(k)F(nk)−−−>化简一下,约掉n,因为是枚举的n的所有倍数,是有无穷多的,k上限是+∞
= ∑ k = 1 + ∞ μ ( k ) ∑ n k ∣ t f ( t ) − − − > 将 F 按 定 义 替 换 , 其 中 t 是 n k 的 所 有 倍 数 =\sum_{k=1}^{+\infty}\mu(k)\sum_{nk|t}f(t)--->_{将F按定义替换,其中t是nk的所有倍数} =∑k=1+∞μ(k)∑nk∣tf(t)−−−>将F按定义替换,其中t是nk的所有倍数
= ∑ n ∣ t f ( t ) ∑ k ∣ t n μ ( k ) − − − > 交 换 μ 和 f 的 枚 举 顺 序 =\sum_{n|t}f(t)\sum_{k|\frac{t}{n}}\mu(k)--->_{交换\mu和f的枚举顺序} =∑n∣tf(t)∑k∣ntμ(k)−−−>交换μ和f的枚举顺序
这里的交换方法和上面的类似。
原本是先枚举
k
k
k,在枚举
t
t
t,且满足
n
k
∣
t
nk|t
nk∣t。
同样的,我们如果要先枚举
t
t
t,在枚举
k
k
k,就要先找到
t
t
t所有可能的取值,然后就是该取值下所有和t配对的
k
k
k。
很明显, t t t的所有取值就是 n n n的所有倍数,所以第一个 ∑ \sum ∑的条件就是 n ∣ t n|t n∣t,然后找到与该 t t t配对的所有的 k k k,使得 t t t和 k k k满足, n k ∣ t nk|t nk∣t,那么就有 n k ∣ t → k ∣ t n nk|t\to k|\frac{t}{n} nk∣t→k∣nt,于是乎,第二个 ∑ \sum ∑的条件就是 k ∣ t n k|\frac{t}{n} k∣nt。
然后,有了
f
(
n
)
=
∑
n
∣
t
f
(
t
)
∑
k
∣
t
n
μ
(
k
)
f(n)=\sum_{n|t}f(t)\sum_{k|\frac{t}{n}}\mu(k)
f(n)=∑n∣tf(t)∑k∣ntμ(k)
同样的套路,只有当 t n = 1 \frac{t}{n}=1 nt=1的时候,才有值,其他的都是 0 0 0。
那么代入 t = n t=n t=n,有:
∑ n ∣ t f ( t ) ∑ k ∣ t n μ ( k ) \sum_{n|t}f(t)\sum_{k|\frac{t}{n}}\mu(k) ∑n∣tf(t)∑k∣ntμ(k)
= ∑ 1 f ( n ) ∗ 1 =\sum_{1}f(n)*1 =∑1f(n)∗1
= f ( n ) =f(n) =f(n)
证毕。
感觉学的晕乎乎的,证明写的也不知道对不对
模版题目
例题1
解法:
转化一下题目:
将每一个点对
(
x
,
y
)
(x,y)
(x,y)对应到坐标轴上,其实就是求在以点
(
a
,
c
)
(a, c)
(a,c)为左下角
(
b
,
d
)
(b,d)
(b,d)为右上角的区域内,满足
g
c
d
(
x
,
y
)
=
k
gcd(x,y)=k
gcd(x,y)=k的点对的个数。
直接求该区域内的点对个数不好求,我们可以利用类似二维前缀和的思想,定义 S ( a , b ) S(a,b) S(a,b)表示以点 ( 1 , 1 ) (1,1) (1,1)为左下角,点 ( a , b ) (a,b) (a,b)为右上角的区域内点对的个数。那么上图中的区域就可以表示为 S ( b , d ) − S ( a − 1 , d ) − S ( b , c − 1 ) + S ( a − 1 , c − 1 ) S(b,d)-S(a-1,d)-S(b,c-1)+S(a-1,c-1) S(b,d)−S(a−1,d)−S(b,c−1)+S(a−1,c−1)。
那么问题就转换成:对于一个以点 ( 1 , 1 ) (1,1) (1,1)为左下角,点 ( a , b ) (a,b) (a,b)为右上角的区域,我们如何快速的求出该区域内满足 g c d ( x , y ) = k gcd(x,y)=k gcd(x,y)=k的所有点对的个数呢?
设答案个数为
a
n
s
ans
ans。
那么有
a
n
s
=
∑
i
=
1
a
∑
j
=
1
b
[
g
c
d
(
i
,
j
)
=
k
]
,
(
如
果
中
括
号
里
的
条
件
成
立
就
是
1
,
否
则
是
0
)
ans=\sum_{i=1}^a\sum_{j=1}^b[gcd(i,j)=k]\ ,_{(如果中括号里的条件成立就是1,否则是0)}
ans=i=1∑aj=1∑b[gcd(i,j)=k] ,(如果中括号里的条件成立就是1,否则是0)
接下来在套用莫比乌斯反演公式之前,我们首先要定义出来
F
(
n
)
F(n)
F(n)和
f
(
n
)
f(n)
f(n)分别表示什么。
(我也不知道是怎么想出来这个定义的,还是记住吧QAQ)
定义
F
(
n
)
=
∑
i
=
1
a
∑
j
=
1
b
[
n
∣
g
c
d
(
i
,
j
)
]
表
示
满
足
g
c
d
(
i
,
j
)
是
n
的
倍
数
的
点
对
个
数
F(n)=\sum_{i=1}^a\sum_{j=1}^b[n|gcd(i,j)] \\表示满足gcd(i,j)是n的倍数的点对个数
F(n)=i=1∑aj=1∑b[n∣gcd(i,j)]表示满足gcd(i,j)是n的倍数的点对个数
定义
f
(
n
)
=
∑
i
=
1
a
∑
j
=
1
b
[
g
c
d
(
i
,
j
)
=
n
]
表
示
g
c
d
(
i
,
j
)
恰
好
等
于
n
的
点
对
的
个
数
f(n)=\sum_{i=1}^a\sum_{j=1}^b[gcd(i,j)=n] \\表示gcd(i,j)恰好等于n的点对的个数
f(n)=i=1∑aj=1∑b[gcd(i,j)=n]表示gcd(i,j)恰好等于n的点对的个数
那么由定义可以推知
F
F
F与
f
f
f之间的关系为:
F
(
n
)
=
∑
n
∣
d
f
(
d
)
F(n)=\sum_{n|d}f(d)
F(n)=n∣d∑f(d)
正好满足莫比乌斯反演公式,反演一下有:
f
(
n
)
=
∑
n
∣
d
μ
(
d
n
)
F
(
d
)
f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d)
f(n)=n∣d∑μ(nd)F(d)
首先,我们要求解 f f f,就要先把 F F F的计算公式推出来。
F ( n ) = ∑ i = 1 a ∑ j = 1 b [ n ∣ g c d ( i , j ) ] F(n)=\sum_{i=1}^a\sum_{j=1}^b[n|gcd(i,j)] F(n)=∑i=1a∑j=1b[n∣gcd(i,j)]
如果说
g
c
d
(
i
,
j
)
gcd(i,j)
gcd(i,j)是
n
n
n的倍数,那么
i
i
i肯定是
n
n
n的倍数,
j
j
j肯定也是
n
n
n的倍数。
在
1
1
1~
a
a
a范围内,是
n
n
n的倍数的数有
⌊
a
n
⌋
\lfloor \frac{a}{n} \rfloor
⌊na⌋个,所以
i
i
i的取值有
⌊
a
n
⌋
\lfloor \frac{a}{n} \rfloor
⌊na⌋种,同理,
j
j
j的取值有
⌊
b
n
⌋
\lfloor \frac{b}{n} \rfloor
⌊nb⌋种,由乘法原理得到,所有这样的
(
i
,
j
)
(i,j)
(i,j)点对有
⌊
a
n
⌋
∗
⌊
b
n
⌋
\lfloor \frac{a}{n} \rfloor*\lfloor \frac{b}{n} \rfloor
⌊na⌋∗⌊nb⌋个。
于是 F ( n ) = ∑ i = 1 a ∑ j = 1 b [ n ∣ g c d ( i , j ) ] = ⌊ a n ⌋ ∗ ⌊ a n ⌋ F(n)=\sum_{i=1}^a\sum_{j=1}^b[n|gcd(i,j)]=\lfloor \frac{a}{n} \rfloor*\lfloor \frac{a}{n} \rfloor F(n)=∑i=1a∑j=1b[n∣gcd(i,j)]=⌊na⌋∗⌊na⌋
所以,
f ( n ) = ∑ n ∣ d μ ( d n ) F ( d ) = ∑ n ∣ d μ ( d n ) ∗ ⌊ a d ⌋ ∗ ⌊ b d ⌋ f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d)=\sum_{n|d}\mu(\frac{d}{n})*\lfloor \frac{a}{d} \rfloor*\lfloor \frac{b}{d} \rfloor f(n)=n∣d∑μ(nd)F(d)=n∣d∑μ(nd)∗⌊da⌋∗⌊db⌋
再次整理一下,设 t = d n t=\frac{d}{n} t=nd,则 d = n t d=nt d=nt。
f
(
n
)
=
∑
n
∣
d
μ
(
d
n
)
∗
⌊
a
d
⌋
∗
⌊
b
d
⌋
f(n)=\sum_{n|d}\mu(\frac{d}{n})*\lfloor \frac{a}{d} \rfloor*\lfloor \frac{b}{d} \rfloor
f(n)=∑n∣dμ(nd)∗⌊da⌋∗⌊db⌋
=
∑
t
=
1
+
∞
μ
(
t
)
∗
⌊
a
n
t
⌋
∗
⌊
b
n
t
⌋
=\sum_{t=1}^{+\infty}\mu(t)*\lfloor \frac{a}{nt} \rfloor*\lfloor \frac{b}{nt} \rfloor
=∑t=1+∞μ(t)∗⌊nta⌋∗⌊ntb⌋
因为 a 、 b 、 n a、b、n a、b、n都是确定的,我们用 a ′ = a n a^{'}=\frac{a}{n} a′=na和 b ′ = b n b^{'}=\frac{b}{n} b′=nb来代替。
那么式子变为
f ( n ) = ∑ t = 1 + ∞ μ ( t ) ∗ ⌊ a ′ t ⌋ ∗ ⌊ b ′ t ⌋ f(n)=\sum_{t=1}^{+\infty}\mu(t)*\lfloor \frac{a^{'}}{t} \rfloor*\lfloor \frac{b^{'}}{t} \rfloor f(n)=∑t=1+∞μ(t)∗⌊ta′⌋∗⌊tb′⌋
当 t > m i n ( a ′ , b ′ ) t>min(a^{'},b^{'}) t>min(a′,b′)的时候,式子的值就等于 0 0 0了,所以我们没必要从 1 1 1枚举到 + ∞ +\infty +∞,上限到 m i n ( a ′ , b ′ ) min(a^{'},b^{'}) min(a′,b′)就够了。
于是乎,我们最终的式子就是!!!
f
(
n
)
=
∑
t
=
1
m
i
n
(
a
′
,
b
′
)
u
(
t
)
∗
⌊
a
′
t
⌋
∗
⌊
b
′
t
⌋
f(n)=\sum_{t=1}^{min(a^{'},b^{'})}u(t)*\lfloor \frac{a^{'}}{t} \rfloor*\lfloor \frac{b^{'}}{t} \rfloor
f(n)=t=1∑min(a′,b′)u(t)∗⌊ta′⌋∗⌊tb′⌋
在计算这个式子的时候,我们可以利用整除分块来降低计算的时间复杂度。
上代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int N = 50010;
int n, m;
int cnt, prime[N], mu[N];
bool vis[N];
void get_prime(int x) //利用线性筛法求莫比乌斯函数
{
mu[1] = 1;
for(int i = 2; i <= x; i ++)
{
if(!vis[i]) prime[cnt ++] = i, mu[i] = -1;
for(int j = 0; prime[j] <= x / i; j ++)
{
vis[prime[j] * i] = true;
if(i % prime[j] == 0) break;
mu[prime[j] * i] = - mu[i];
}
}
for(int i = 1; i <= x; i ++) mu[i] += mu[i - 1]; //对mu进行一个前缀和
}
LL S(int a, int b, int k) //计算左下角(1, 1)右上角(a, b)的区域内的点对个数
{
a /= k; b /= k;
int t = min(a, b);
LL res = 0;
for(int l = 1, r; l <= t; l = r + 1)
{
r = min(t, min(a / (a / l), b / (b / l)));
res += (LL)(mu[r] - mu[l - 1]) * (a / l) * (b / l);
}
return res;
}
int main()
{
#ifdef LOCAL
freopen("in.in", "r", stdin);
freopen("out.out", "w", stdout);
#endif
get_prime(N - 1); //预处理求出所有的莫比乌斯函数
int T;
scanf("%d", &T);
while(T --)
{
int a, b, c, d, k;
scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
printf("%lld\n", S(b, d, k) - S(a - 1, d, k) - S(b, c - 1, k) + S(a - 1, c - 1, k));
}
return 0;
}
( 趁热打铁,再来一道)
P1447 [NOI2010] 能量采集
(题面就不在这里贴了)
解法:
一共 n ∗ m n*m n∗m个植物,每一个植物都有一个 k k k值,然后每一个植物都会产生 2 k + 1 2k+1 2k+1的能量浪费,求总共有多少能量被浪费。
因为这个 2 k + 1 2k+1 2k+1中的 1 1 1是固定下来的,所以对于n*m个植物,肯定会有 n ∗ m n*m n∗m点浪费,先把这个固定的 1 1 1产生的贡献 n ∗ m n*m n∗m加上。于是,每一个植物的能量浪费就变成了 2 k 2k 2k,我们只需要统计所有的植物的 k k k值的和, K = k 1 + k 2 + . . . + k n m K=k_1+k_2+...+k_{nm} K=k1+k2+...+knm,然后在乘 2 2 2,最后答案 a n s = 2 K + n ∗ m ans=2K+n*m ans=2K+n∗m。
对于每一个点,它的
k
k
k值怎么求?
由题意应该很容易想到对于一个点
(
i
,
j
)
(i,j)
(i,j),它的
k
=
g
c
d
(
i
,
j
)
−
1
k=gcd(i,j)-1
k=gcd(i,j)−1。
于是,
K
=
∑
i
=
1
n
∑
j
=
1
m
(
g
c
d
(
i
,
j
)
−
1
)
=
∑
i
=
1
n
∑
j
=
1
m
g
c
d
(
i
,
j
)
−
n
∗
m
K=\sum_{i=1}^n\sum_{j=1}^m(gcd(i,j)-1)=\sum_{i=1}^n\sum_{j=1}^mgcd(i,j)-n*m
K=i=1∑nj=1∑m(gcd(i,j)−1)=i=1∑nj=1∑mgcd(i,j)−n∗m
由于
K
K
K的特殊形式,答案ans也可以化简一下
a
n
s
=
2
∗
∑
i
=
1
n
∑
j
=
1
m
g
c
d
(
i
,
j
)
−
n
∗
m
ans=2*\sum_{i=1}^n\sum_{j=1}^mgcd(i,j)-n*m
ans=2∗i=1∑nj=1∑mgcd(i,j)−n∗m
问题变成了求 ∑ i = 1 n ∑ j = 1 m g c d ( i , j ) \sum_{i=1}^n\sum_{j=1}^mgcd(i,j) ∑i=1n∑j=1mgcd(i,j)。
我们要把该式子变成类似于上一题的形式。
可以先枚举所有的 g c d ( i , j ) gcd(i,j) gcd(i,j)的值d,然后统计有多少个 ( i , j ) (i,j) (i,j)对的 g c d = d gcd=d gcd=d,假设求出来 s s s对,那么,这个约数 d d d产生的贡献就是 d ∗ s d*s d∗s。
于是,式子就变成了这样(假定
n
<
m
n<m
n<m)
∑
i
=
1
n
∑
j
=
1
m
g
c
d
(
i
,
j
)
=
∑
d
=
1
n
d
∗
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
d
]
\sum_{i=1}^n\sum_{j=1}^mgcd(i,j)=\sum_{d=1}^nd*\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=d]
i=1∑nj=1∑mgcd(i,j)=d=1∑nd∗i=1∑nj=1∑m[gcd(i,j)=d]
然后把这个拿出来: ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = d ] \sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=d] ∑i=1n∑j=1m[gcd(i,j)=d]
类似上一题的定义方式(不能说是类似,应该说是一模一样 ):
定义
F
(
n
)
=
∑
i
=
1
a
∑
j
=
1
b
[
n
∣
g
c
d
(
i
,
j
)
]
表
示
满
足
g
c
d
(
i
,
j
)
是
n
的
倍
数
的
点
对
个
数
F(n)=\sum_{i=1}^a\sum_{j=1}^b[n|gcd(i,j)] \\表示满足gcd(i,j)是n的倍数的点对个数
F(n)=i=1∑aj=1∑b[n∣gcd(i,j)]表示满足gcd(i,j)是n的倍数的点对个数
定义
f
(
n
)
=
∑
i
=
1
a
∑
j
=
1
b
[
g
c
d
(
i
,
j
)
=
n
]
表
示
g
c
d
(
i
,
j
)
恰
好
等
于
n
的
点
对
的
个
数
f(n)=\sum_{i=1}^a\sum_{j=1}^b[gcd(i,j)=n] \\表示gcd(i,j)恰好等于n的点对的个数
f(n)=i=1∑aj=1∑b[gcd(i,j)=n]表示gcd(i,j)恰好等于n的点对的个数
接下来就和上一题的推理方式一样了,我就不推了。
反正最后求出来 f ( n ) f(n) f(n)的表达式是这样的。
f ( n ) = ∑ t = 1 m i n ( a , b ) μ ( t ) ∗ ⌊ a t ⌋ ∗ ⌊ b t ⌋ 其 中 a = N d , b = M d N 和 M 是 题 目 中 的 范 围 , d 是 当 前 枚 举 的 约 数 f(n)=\sum_{t=1}^{min(a,b)}\mu(t)*\lfloor \frac{a}{t} \rfloor*\lfloor \frac{b}{t} \rfloor \\其中a=\frac{N}{d},b=\frac{M}{d} \\N和M是题目中的范围,d是当前枚举的约数 f(n)=t=1∑min(a,b)μ(t)∗⌊ta⌋∗⌊tb⌋其中a=dN,b=dMN和M是题目中的范围,d是当前枚举的约数
废话少说,上代码!!!
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int n, m;
int cnt, prime[N], mu[N];
bool vis[N];
void get_prime(int x)
{
mu[1] = 1;
for(int i = 2; i <= x; i ++)
{
if(!vis[i]) prime[cnt ++] = i, mu[i] = -1;
for(int j = 0; prime[j] <= x / i; j ++)
{
vis[prime[j] * i] = true;
if(i % prime[j] == 0) break;
mu[prime[j] * i] = -mu[i];
}
}
for(int i = 1; i <= x; i ++) mu[i] += mu[i - 1];
}
LL solve(int n, int m, int d)
{
n /= d; m /= d;
int t = min(n, m);
LL res = 0;
for(int l = 1, r; l <= t; l = r + 1)
{
r = min(t, min(n / (n / l), m / (m / l)));
res += (LL)(mu[r] - mu[l - 1]) * (n / l) * (m / l);
}
return res;
}
int main()
{
#ifdef LOCAL
freopen("in.in", "r", stdin);
freopen("out.out", "w", stdout);
#endif
cin >> n >> m;
int t = min(n, m);
get_prime(t);
LL res = 0;
for(int d = 1; d <= t; d ++) //枚举所有gcd(i, j)的值
res += d * solve(n, m, d);
res = res * 2 - (LL)n * m;
cout << res << endl;
return 0;
}
update-2021.10.8
进阶题目
P1829 [国家集训队]Crash的数字表格 / JZPTAB
题目大意:
求
∑
i
=
1
N
∑
j
=
1
M
l
c
m
(
i
,
j
)
(
m
o
d
20101009
)
\sum_{i=1}^N\sum_{j=1}^Mlcm(i,j)\ \ (mod\ 20101009)
i=1∑Nj=1∑Mlcm(i,j) (mod 20101009)
做法:
- 对式子进行变形:
∑ i = 1 N ∑ j = 1 M l c m ( i , j ) \ \ \ \ \sum_{i=1}^N\sum_{j=1}^Mlcm(i,j) ∑i=1N∑j=1Mlcm(i,j)
= ∑ i = 1 N ∑ j = 1 M i j g c d ( i , j ) =\sum_{i=1}^N\sum_{j=1}^M\frac{ij}{gcd(i,j)} =∑i=1N∑j=1Mgcd(i,j)ij
= ∑ d = 1 T ∑ i = 1 N ∑ j = 1 M i j d ∗ [ g c d ( i , j ) = d ] , ( 其 中 T = m i n ( N , M ) =\sum_{d=1}^T\sum_{i=1}^N\sum_{j=1}^M\frac{ij}{d}*[gcd(i,j)=d],_{(其中T=min(N,M)} =∑d=1T∑i=1N∑j=1Mdij∗[gcd(i,j)=d],(其中T=min(N,M)
= ∑ d = 1 T 1 d ∑ i = 1 N ∑ j = 1 M i j ∗ [ g c d ( i , j ) = d ] =\sum_{d=1}^T\frac{1}{d}\sum_{i=1}^N\sum_{j=1}^Mij*[gcd(i,j)=d] =∑d=1Td1∑i=1N∑j=1Mij∗[gcd(i,j)=d]
= ∑ d = 1 T 1 d ∑ i = 1 N d ∑ j = 1 M d i j ∗ d 2 ∗ [ g c d ( i , j ) = 1 ] =\sum_{d=1}^T\frac{1}{d}\sum_{i=1}^{\frac{N}{d}}\sum_{j=1}^{\frac{M}{d}}ij*d^2*[gcd(i,j)=1] =∑d=1Td1∑i=1dN∑j=1dMij∗d2∗[gcd(i,j)=1]
= ∑ d = 1 T d ∑ i = 1 N d ∑ j = 1 M d i j ∗ [ g c d ( i , j ) = 1 ] =\sum_{d=1}^Td\sum_{i=1}^{\frac{N}{d}}\sum_{j=1}^{\frac{M}{d}}ij*[gcd(i,j)=1] =∑d=1Td∑i=1dN∑j=1dMij∗[gcd(i,j)=1]
设函数 g ( N , M ) g(N,M) g(N,M)表示 ∑ i = 1 N ∑ j = 1 M i j ∗ [ g c d ( i , j ) = 1 ] \sum_{i=1}^N\sum_{j=1}^Mij*[gcd(i,j)=1] ∑i=1N∑j=1Mij∗[gcd(i,j)=1]
则上式等于: ∑ d = 1 T d ∗ g ( N d , M d ) \sum_{d=1}^Td*g(\frac{N}{d},\frac{M}{d}) ∑d=1Td∗g(dN,dM)
- 接下来的问题变为如何快速的求出 g ( N , M ) g(N,M) g(N,M).
g ( N , M ) = ∑ i = 1 N ∑ j = 1 M i j ∗ [ g c d ( i , j ) = 1 ] g(N,M)=\sum_{i=1}^N\sum_{j=1}^Mij*[gcd(i,j)=1] g(N,M)=i=1∑Nj=1∑Mij∗[gcd(i,j)=1]
- 这里就可以使用莫比乌斯反演来求:
设
F
(
n
)
F(n)
F(n)表示
∑
i
=
1
N
∑
j
=
1
M
i
j
∗
[
n
∣
g
c
d
(
i
,
j
)
]
\sum_{i=1}^N\sum_{j=1}^Mij*[n|gcd(i,j)]
∑i=1N∑j=1Mij∗[n∣gcd(i,j)]。
设
f
(
n
)
f(n)
f(n)表示
∑
i
=
1
N
∑
j
=
1
M
i
j
∗
[
g
c
d
(
i
,
j
)
=
n
]
\sum_{i=1}^N\sum_{j=1}^Mij*[gcd(i,j)=n]
∑i=1N∑j=1Mij∗[gcd(i,j)=n]。
则有
F
(
n
)
=
∑
n
∣
d
f
(
d
)
F(n)=\sum_{n|d}f(d)
F(n)=∑n∣df(d)。
反演一下有
f
(
n
)
=
∑
n
∣
d
μ
(
d
n
)
F
(
d
)
f(n)=\sum_{n|d}\mu{(\frac{d}{n})}F(d)
f(n)=∑n∣dμ(nd)F(d)。
- 我们要求的是 f ( 1 ) f(1) f(1)。
f ( 1 ) = ∑ d = 1 + ∞ μ ( d ) F ( d ) f(1)=\sum_{d=1}^{+\infty}\mu(d)F(d) f(1)=∑d=1+∞μ(d)F(d)。
- 然后我们需要推导出 F ( n ) F(n) F(n)的表达式。
F ( n ) = ∑ i = 1 N ∑ j = 1 M i j ∗ [ n ∣ g c d ( i , j ) ] F(n)=\sum_{i=1}^N\sum_{j=1}^Mij*[n|gcd(i,j)] F(n)=∑i=1N∑j=1Mij∗[n∣gcd(i,j)]
= ∑ i = 1 N n ∑ j = 1 M n i j ∗ n 2 =\sum_{i=1}^{\frac{N}{n}}\sum_{j=1}^{\frac{M}{n}}ij*n^2 =∑i=1nN∑j=1nMij∗n2
= n 2 ∑ i = 1 N n i ∑ j = 1 M n j =n^2\sum_{i=1}^{\frac{N}{n}}i\sum_{j=1}^{\frac{M}{n}}j =n2∑i=1nNi∑j=1nMj
= n 2 ∗ N n ( N n + 1 ) 2 ∗ M n ( M n + 1 ) 2 , ( 注 意 , 此 处 的 除 法 都 是 整 除 ) =n^2*\frac{\frac{N}{n}(\frac{N}{n}+1)}{2}*\frac{\frac{M}{n}(\frac{M}{n}+1)}{2},_{(注意,此处的除法都是整除)} =n2∗2nN(nN+1)∗2nM(nM+1),(注意,此处的除法都是整除)
于是得到, F ( n ) = n 2 ∗ N n ( N n + 1 ) 2 ∗ M n ( M n + 1 ) 2 F(n)=n^2*\frac{\frac{N}{n}(\frac{N}{n}+1)}{2}*\frac{\frac{M}{n}(\frac{M}{n}+1)}{2} F(n)=n2∗2nN(nN+1)∗2nM(nM+1)
则
f
(
1
)
=
∑
d
=
1
+
∞
μ
(
d
)
F
(
d
)
f(1)=\sum_{d=1}^{+\infty}\mu(d)F(d)
f(1)=∑d=1+∞μ(d)F(d)
=
∑
i
=
1
+
∞
μ
(
i
)
F
(
i
)
,
(
换
个
变
量
名
表
示
)
=\sum_{i=1}^{+\infty}\mu(i)F(i),_{(换个变量名表示)}
=∑i=1+∞μ(i)F(i),(换个变量名表示)
= ∑ i = 1 + ∞ μ ( i ) ∗ i 2 ∗ N i ( N i + 1 ) 2 ∗ M i ( M i + 1 ) 2 =\sum_{i=1}^{+\infty}\mu(i)*i^2*\frac{\frac{N}{i}(\frac{N}{i}+1)}{2}*\frac{\frac{M}{i}(\frac{M}{i}+1)}{2} =∑i=1+∞μ(i)∗i2∗2iN(iN+1)∗2iM(iM+1)
= ∑ i = 1 m i n ( N , M ) μ ( i ) ∗ i 2 ∗ N i ( N i + 1 ) 2 ∗ M i ( M i + 1 ) 2 =\sum_{i=1}^{min(N,M)}\mu(i)*i^2*\frac{\frac{N}{i}(\frac{N}{i}+1)}{2}*\frac{\frac{M}{i}(\frac{M}{i}+1)}{2} =∑i=1min(N,M)μ(i)∗i2∗2iN(iN+1)∗2iM(iM+1)
- 最终,我们得到
∑ i = 1 N ∑ j = 1 M l c m ( i , j ) = ∑ d = 1 T d ∗ g ( N d , M d ) \sum_{i=1}^N\sum_{j=1}^Mlcm(i,j)=\sum_{d=1}^Td*g(\frac{N}{d},\frac{M}{d}) ∑i=1N∑j=1Mlcm(i,j)=∑d=1Td∗g(dN,dM)
g ( N , M ) = f ( 1 ) = ∑ i = 1 m i n ( N , M ) μ ( i ) ∗ i 2 ∗ N i ( N i + 1 ) 2 ∗ M i ( M i + 1 ) 2 g(N,M)=f(1)=\sum_{i=1}^{min(N,M)}\mu(i)*i^2*\frac{\frac{N}{i}(\frac{N}{i}+1)}{2}*\frac{\frac{M}{i}(\frac{M}{i}+1)}{2} g(N,M)=f(1)=∑i=1min(N,M)μ(i)∗i2∗2iN(iN+1)∗2iM(iM+1)
接下来就可以愉快的做题了!
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int N = 1e7 + 10, MOD = 20101009;
int cnt, prime[N], mu[N];
LL sum[N]; //mu[i] * i * i的前缀和
bool vis[N];
void init(int x)
{
mu[1] = 1;
for(int i = 2; i <= x; i ++)
{
if(!vis[i]) prime[cnt ++] = i, mu[i] = -1;
for(int j = 0; prime[j] <= x / i; j ++)
{
vis[prime[j] * i] = true;
if(i % prime[j] == 0) break;
mu[prime[j] * i] = -mu[i];
}
}
for(int i = 1; i <= x; i ++)
sum[i] = (sum[i - 1] + (LL)i * i % MOD * (mu[i] + MOD) % MOD) % MOD;
}
LL cal(int x, int y)
{
return (((LL)x * (x + 1) / 2) % MOD) * (((LL)y * (y + 1) / 2) % MOD) % MOD;
}
LL g(int n, int m)
{
int t = min(n, m);
LL res = 0;
for(int l = 1, r; l <= t; l = r + 1)
{
r = min(t, min(n / (n / l), m / (m / l)));
res = (res + (sum[r] - sum[l - 1] + MOD) % MOD * cal(n / l, m / l)% MOD) % MOD;
}
return res;
}
int main()
{
#ifdef LOCAL
freopen("in.in", "r", stdin);
freopen("out.out", "w", stdout);
#endif
int n, m;
cin >> n >> m;
int t = min(n, m);
init(t);
LL ans = 0;
for(int d = 1; d <= t; d ++)
ans = (ans + (LL)d * g(n / d, m / d)) % MOD;
cout << ans << endl;
return 0;
}
AcWing 1358. 约数个数和
做法:
- 首先, d ( i j ) = ∑ x ∣ i ∑ y ∣ j [ g c d ( x , y ) = 1 ] d(ij)=\sum_{x|i}\sum_{y|j}[gcd(x,y)=1] d(ij)=∑x∣i∑y∣j[gcd(x,y)=1](根本想不到的转化QAQ)。
证明有点麻烦,不贴了。
所以,原式子等于:
∑
i
=
1
N
∑
j
=
1
M
d
(
i
j
)
=
∑
i
=
1
N
∑
j
=
1
M
∑
x
∣
i
∑
y
∣
j
[
g
c
d
(
x
,
y
)
=
1
]
\sum_{i=1}^N\sum_{j=1}^Md(ij)=\sum_{i=1}^N\sum_{j=1}^M\sum_{x|i}\sum_{y|j}[gcd(x,y)=1]
i=1∑Nj=1∑Md(ij)=i=1∑Nj=1∑Mx∣i∑y∣j∑[gcd(x,y)=1]
- 对式子进行化简:
∑
i
=
1
N
∑
j
=
1
M
∑
x
∣
i
∑
y
∣
j
[
g
c
d
(
x
,
y
)
=
1
]
\ \ \ \ \sum_{i=1}^N\sum_{j=1}^M\sum_{x|i}\sum_{y|j}[gcd(x,y)=1]
∑i=1N∑j=1M∑x∣i∑y∣j[gcd(x,y)=1]
=
∑
x
=
1
N
∑
y
=
1
M
∑
x
∣
i
∑
y
∣
j
[
g
c
d
(
x
,
y
)
=
1
]
,
(
交
换
一
下
x
,
y
,
i
,
j
的
枚
举
顺
序
)
=\sum_{x=1}^N\sum_{y=1}^M\sum_{x|i}\sum_{y|j}[gcd(x,y)=1],_{(交换一下x,y,i,j的枚举顺序)}
=∑x=1N∑y=1M∑x∣i∑y∣j[gcd(x,y)=1],(交换一下x,y,i,j的枚举顺序)
= ∑ x = 1 N ∑ y = 1 M [ g c d ( x , y ) = 1 ] ∑ x ∣ i ∑ y ∣ j 1 =\sum_{x=1}^N\sum_{y=1}^M[gcd(x,y)=1]\sum_{x|i}\sum_{y|j}1 =∑x=1N∑y=1M[gcd(x,y)=1]∑x∣i∑y∣j1
= ∑ x = 1 N ∑ y = 1 M [ g c d ( x , y ) = 1 ] ∗ ⌊ N x ⌋ ∗ ⌊ M y ⌋ =\sum_{x=1}^N\sum_{y=1}^M[gcd(x,y)=1]*\lfloor \frac{N}{x} \rfloor*\lfloor \frac{M}{y} \rfloor =∑x=1N∑y=1M[gcd(x,y)=1]∗⌊xN⌋∗⌊yM⌋
= ∑ i = 1 N ∑ j = 1 M [ g c d ( i , j ) = 1 ] ∗ ⌊ N i ⌋ ∗ ⌊ M j ⌋ , ( 换 一 下 变 量 名 , x 变 成 i , y 变 成 j ) =\sum_{i=1}^N\sum_{j=1}^M[gcd(i,j)=1]*\lfloor \frac{N}{i} \rfloor*\lfloor \frac{M}{j} \rfloor,_{(换一下变量名,x变成i,y变成j)} =∑i=1N∑j=1M[gcd(i,j)=1]∗⌊iN⌋∗⌊jM⌋,(换一下变量名,x变成i,y变成j)
- 到这里后,就可以开始进行莫比乌斯反演了。
设 F ( n ) = ∑ i = 1 N ∑ j = 1 M [ n ∣ g c d ( i , j ) ] ∗ ⌊ N i ⌋ ∗ ⌊ M j ⌋ F(n)=\sum_{i=1}^N\sum_{j=1}^M[n|gcd(i,j)]*\lfloor \frac{N}{i} \rfloor*\lfloor \frac{M}{j} \rfloor F(n)=∑i=1N∑j=1M[n∣gcd(i,j)]∗⌊iN⌋∗⌊jM⌋。
设 f ( n ) = ∑ i = 1 N ∑ j = 1 M [ g c d ( i , j ) = n ] ∗ ⌊ N i ⌋ ∗ ⌊ M j ⌋ f(n)=\sum_{i=1}^N\sum_{j=1}^M[gcd(i,j)=n]*\lfloor \frac{N}{i} \rfloor*\lfloor \frac{M}{j} \rfloor f(n)=∑i=1N∑j=1M[gcd(i,j)=n]∗⌊iN⌋∗⌊jM⌋。
则有: F ( n ) = ∑ n ∣ d f ( d ) F(n)=\sum_{n|d}f(d) F(n)=∑n∣df(d)。
反演一下有: f ( n ) = ∑ n ∣ d μ ( d n ) F ( d ) f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d) f(n)=∑n∣dμ(nd)F(d)。
我们要求的是 f ( 1 ) = ∑ d = 1 + ∞ μ ( d ) F ( d ) f(1)=\sum_{d=1}^{+\infty}\mu(d)F(d) f(1)=∑d=1+∞μ(d)F(d)。
- 接下来推导出 F ( n ) F(n) F(n)的表达式。
F ( n ) = ∑ i = 1 N ∑ j = 1 M [ n ∣ g c d ( i , j ) ] ∗ ⌊ N i ⌋ ∗ ⌊ M j ⌋ F(n)=\sum_{i=1}^N\sum_{j=1}^M[n|gcd(i,j)]*\lfloor \frac{N}{i} \rfloor*\lfloor \frac{M}{j} \rfloor F(n)=i=1∑Nj=1∑M[n∣gcd(i,j)]∗⌊iN⌋∗⌊jM⌋
∑ i = 1 N ∑ j = 1 M [ n ∣ g c d ( i , j ) ] ∗ ⌊ N i ⌋ ∗ ⌊ M j ⌋ \sum_{i=1}^N\sum_{j=1}^M[n|gcd(i,j)]*\lfloor \frac{N}{i} \rfloor*\lfloor \frac{M}{j} \rfloor ∑i=1N∑j=1M[n∣gcd(i,j)]∗⌊iN⌋∗⌊jM⌋
= ∑ i = 1 N n ∑ j = 1 M n ⌊ N n i ⌋ ∗ ⌊ M n j ⌋ =\sum_{i=1}^{\frac{N}{n}}\sum_{j=1}^{\frac{M}{n}}\lfloor \frac{N}{ni} \rfloor*\lfloor \frac{M}{nj} \rfloor =∑i=1nN∑j=1nM⌊niN⌋∗⌊njM⌋
= ∑ i = 1 N n ⌊ N n i ⌋ ∗ ∑ j = 1 M n ⌊ M n j ⌋ =\sum_{i=1}^{\frac{N}{n}}\lfloor \frac{N}{ni} \rfloor*\sum_{j=1}^{\frac{M}{n}}\lfloor \frac{M}{nj} \rfloor =∑i=1nN⌊niN⌋∗∑j=1nM⌊njM⌋
设 g ( n ) = ∑ i = 1 n ⌊ n i ⌋ g(n)=\sum_{i=1}^n\lfloor \frac{n}{i} \rfloor g(n)=∑i=1n⌊in⌋。
于是, F ( n ) = g ( N n ) ∗ g ( M n ) F(n)=g(\frac{N}{n})*g(\frac{M}{n}) F(n)=g(nN)∗g(nM)。
- 那么, f ( 1 ) f(1) f(1)的最终式子是:
f ( 1 ) = ∑ i = 1 + ∞ μ ( i ) F ( i ) f(1)=\sum_{i=1}^{+\infty}\mu(i)F(i) f(1)=∑i=1+∞μ(i)F(i)
= ∑ i = 1 m i n ( N , M ) μ ( i ) ∗ g ( N i ) ∗ g ( M i ) =\sum_{i=1}^{min(N,M)}\mu(i)*g(\frac{N}{i})*g(\frac{M}{i}) =∑i=1min(N,M)μ(i)∗g(iN)∗g(iM)
( 除 法 都 是 整 除 , 所 以 上 面 的 式 子 就 是 这 个 ) _{(除法都是整除,所以上面的式子就是这个)} (除法都是整除,所以上面的式子就是这个)
= ∑ i = 1 m i n ( N , M ) μ ( i ) ∗ g ( ⌊ N i ⌋ ) ∗ g ( ⌊ M i ⌋ ) =\sum_{i=1}^{min(N,M)}\mu(i)*g(\lfloor\frac{N}{i}\rfloor)*g(\lfloor\frac{M}{i}\rfloor) =∑i=1min(N,M)μ(i)∗g(⌊iN⌋)∗g(⌊iM⌋)
( 我 们 求 这 个 式 子 的 时 候 也 是 用 整 除 分 块 来 缩 短 时 间 ) _{(我们求这个式子的时候也是用整除分块来缩短时间)} (我们求这个式子的时候也是用整除分块来缩短时间)
其中, g ( n ) = ∑ i = 1 n ⌊ n i ⌋ g(n)=\sum_{i=1}^n\lfloor \frac{n}{i} \rfloor g(n)=∑i=1n⌊in⌋。
因为要用到多次 g ( n ) g(n) g(n),所以,可以提前把 g ( 1 ) g(1) g(1)~ g ( N ) g(N) g(N)都预处理出来。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int N = 5e4 + 10;
int cnt, prime[N], mu[N], g[N];
bool vis[N];
void init(int x)
{
mu[1] = 1;
for(int i = 2; i <= x; i ++)
{
if(!vis[i]) prime[cnt ++] = i, mu[i] = -1;
for(int j = 0; prime[j] <= x / i; j ++)
{
vis[prime[j] * i] = true;
if(i % prime[j] == 0) break;
mu[prime[j] * i] = -mu[i];
}
}
for(int i = 1; i <= x; i ++) mu[i] += mu[i - 1];
for(int i = 1; i <= x; i ++)
{
for(int l = 1, r; l <= i; l = r + 1)
{
r = min(i, i / (i / l));
g[i] += (r - l + 1) * ( i / l);
}
}
}
int main()
{
#ifdef LOCAL
freopen("in.in", "r", stdin);
freopen("out.out", "w", stdout);
#endif
init(N - 1);
int T; scanf("%d", &T);
while(T --)
{
int n, m;
scanf("%d%d", &n, &m);
int t = min(n, m);
LL ans = 0;
for(int l = 1, r; l <= t; l = r + 1)
{
r = min(t, min(n / (n / l), m / (m / l)));
ans += (LL)(mu[r] - mu[l - 1]) * g[n / l] * g[m / l];
}
printf("%lld\n", ans);
}
return 0;
}