传送门
其实就是一个性质:
d
(
a
b
)
=
∑
i
∣
a
∑
j
∣
b
[
g
c
d
(
i
,
j
)
=
=
1
]
d(ab)=\sum_{i|a}\sum_{j|b}[gcd(i,j)==1]
d(ab)=i∣a∑j∣b∑[gcd(i,j)==1]
看到这种两个乘起来的数论函数,处理办法往往都是想方设法把这两个数拆开。比如:
φ
(
i
j
)
=
φ
(
i
)
∗
φ
(
j
)
∗
g
c
d
(
i
,
j
)
φ
(
g
c
d
(
i
,
j
)
)
\varphi(ij)=\varphi(i)*\varphi(j)*\frac{gcd(i,j)}{\varphi(gcd(i,j))}
φ(ij)=φ(i)∗φ(j)∗φ(gcd(i,j))gcd(i,j)
证明可以通过把它们质因数分解得到:
设
a
b
=
∏
p
i
t
i
,
a
=
∏
p
i
a
i
,
b
=
∏
p
i
b
i
ab=\prod p_i^{t_i},a=\prod p_i^{a_i},b=\prod p_i^{b_i}
ab=∏piti,a=∏piai,b=∏pibi,那么有
t
i
=
a
i
+
b
i
t_i=a_i+b_i
ti=ai+bi。
令
i
=
∏
p
i
x
i
,
j
=
∏
p
i
y
i
i=\prod p_i^{x_i},j=\prod p_i^{y_i}
i=∏pixi,j=∏piyi。
由于
g
c
d
(
i
,
j
)
=
1
gcd(i,j)=1
gcd(i,j)=1,那么有:
∀
i
,
x
i
=
0
o
r
y
i
=
0
\forall i,x_i=0\ \ or\ \ y_i=0
∀i,xi=0 or yi=0
若
x
i
=
0
x_i=0
xi=0,那么
y
i
∈
[
0
,
b
i
]
y_i\in[0,b_i]
yi∈[0,bi],共
b
i
+
1
b_i+1
bi+1种取值。
若
y
i
=
0
y_i=0
yi=0,那么
x
i
∈
[
0
,
a
i
]
x_i\in[0,a_i]
xi∈[0,ai],共
a
i
+
1
a_i+1
ai+1种取值。
而
x
i
=
0
a
n
d
y
i
=
0
x_i=0\ \ and\ \ y_i=0
xi=0 and yi=0被算了两次,那么对于一个
i
i
i,
x
i
x_i
xi和
y
i
y_i
yi的取值方案共有
(
a
i
+
1
)
+
(
b
i
+
1
)
−
1
=
a
i
+
b
i
+
1
(a_i+1)+(b_i+1)-1=a_i+b_i+1
(ai+1)+(bi+1)−1=ai+bi+1种。
根据乘法原理,可以得到:
∑
i
∣
a
∑
j
∣
b
[
g
c
d
(
i
,
j
)
=
=
1
]
\sum_{i|a}\sum_{j|b}[gcd(i,j)==1]
i∣a∑j∣b∑[gcd(i,j)==1]
=
∏
(
a
i
+
b
i
+
1
)
=\prod (a_i+b_i+1)
=∏(ai+bi+1)
=
∏
(
t
i
+
1
)
=\prod (t_i+1)
=∏(ti+1)
=
d
(
a
b
)
=d(ab)
=d(ab)
于是得证。
接下来推式子就好:
∑
i
=
1
n
∑
j
=
1
m
d
(
i
j
)
\sum_{i=1}^{n} \sum_{j=1}^{m}d(ij)
i=1∑nj=1∑md(ij)
=
∑
i
=
1
n
∑
j
=
1
m
∑
a
∣
i
∑
b
∣
j
[
g
c
d
(
a
,
b
)
=
=
1
]
=\sum_{i=1}^{n} \sum_{j=1}^{m} \sum_{a|i} \sum_{b|j} [gcd(a,b)==1]
=i=1∑nj=1∑ma∣i∑b∣j∑[gcd(a,b)==1]
莫比乌斯反演:
=
∑
i
=
1
n
∑
j
=
1
m
∑
a
∣
i
∑
b
∣
j
∑
d
∣
g
c
d
(
a
,
b
)
μ
(
d
)
=\sum_{i=1}^{n} \sum_{j=1}^{m} \sum_{a|i} \sum_{b|j} \sum_{d|gcd(a,b)} \mu(d)
=i=1∑nj=1∑ma∣i∑b∣j∑d∣gcd(a,b)∑μ(d)
=
∑
i
=
1
n
∑
j
=
1
m
∑
a
∣
i
∑
b
∣
j
∑
d
∣
a
,
d
∣
b
μ
(
d
)
=\sum_{i=1}^{n} \sum_{j=1}^{m} \sum_{a|i} \sum_{b|j} \sum_{d|a,d|b} \mu(d)
=i=1∑nj=1∑ma∣i∑b∣j∑d∣a,d∣b∑μ(d)
交换
a
,
b
a,b
a,b和
i
,
j
i,j
i,j的枚举顺序:
=
∑
a
=
1
n
∑
b
=
1
m
∑
i
=
1
⌊
n
a
⌋
∑
j
=
1
⌊
m
b
⌋
∑
d
∣
a
,
d
∣
b
μ
(
d
)
=\sum_{a=1}^{n} \sum_{b=1}^{m} \sum_{i=1}^{\lfloor \frac{n}{a} \rfloor} \sum_{j=1}^{\lfloor \frac{m}{b} \rfloor} \sum_{d|a,d|b} \mu(d)
=a=1∑nb=1∑mi=1∑⌊an⌋j=1∑⌊bm⌋d∣a,d∣b∑μ(d)
=
∑
a
=
1
n
∑
b
=
1
m
⌊
n
a
⌋
⌊
m
b
⌋
∑
d
∣
a
,
d
∣
b
μ
(
d
)
=\sum_{a=1}^{n} \sum_{b=1}^{m} \lfloor \frac{n}{a} \rfloor \lfloor \frac{m}{b} \rfloor \sum_{d|a,d|b} \mu(d)
=a=1∑nb=1∑m⌊an⌋⌊bm⌋d∣a,d∣b∑μ(d)
提前枚举
d
d
d:
=
∑
d
=
1
n
μ
(
d
)
∑
a
=
1
⌊
n
d
⌋
∑
b
=
1
⌊
m
d
⌋
⌊
n
a
∗
d
⌋
⌊
m
b
∗
d
⌋
=\sum_{d=1}^{n} \mu(d)\sum_{a=1}^{ \lfloor \frac{n}{d} \rfloor} \sum_{b=1}^{ \lfloor \frac{m}{d} \rfloor} \lfloor \frac{n}{a*d} \rfloor \lfloor \frac{m}{b*d} \rfloor
=d=1∑nμ(d)a=1∑⌊dn⌋b=1∑⌊dm⌋⌊a∗dn⌋⌊b∗dm⌋
=
∑
d
=
1
n
μ
(
d
)
∑
a
=
1
⌊
n
d
⌋
⌊
⌊
n
d
⌋
a
⌋
∑
b
=
1
⌊
m
d
⌋
⌊
⌊
m
d
⌋
b
⌋
=\sum_{d=1}^{n} \mu(d)\sum_{a=1}^{ \lfloor \frac{n}{d} \rfloor} \lfloor \frac{\lfloor \frac{n}{d} \rfloor}{a} \rfloor \sum_{b=1}^{ \lfloor \frac{m}{d} \rfloor}\lfloor \frac{\lfloor \frac{m}{d} \rfloor}{b} \rfloor
=d=1∑nμ(d)a=1∑⌊dn⌋⌊a⌊dn⌋⌋b=1∑⌊dm⌋⌊b⌊dm⌋⌋
我们令
f
(
n
)
=
∑
i
=
1
n
⌊
n
i
⌋
f(n)=\sum_{i=1}^{n} \lfloor \frac{n}{i} \rfloor
f(n)=i=1∑n⌊in⌋
f
f
f其实就是约数个数前缀和,而约数个数函数可以线性筛。筛完之后求个前缀和就行了。详情看这里
其实如果不知道这个东西的筛法,整除分块预处理也是可以的。
答案即为:
a
n
s
=
∑
d
=
1
n
μ
(
d
)
∗
f
(
n
d
)
∗
f
(
m
d
)
ans=\sum_{d=1}^{n} \mu(d)*f(\frac{n}{d})*f(\frac{m}{d})
ans=d=1∑nμ(d)∗f(dn)∗f(dm)
n
d
\frac{n}{d}
dn最多有
n
\sqrt n
n种取值,
m
d
\frac{m}{d}
dm最多有
m
\sqrt m
m种取值,所以整除分块一共最多有
(
n
+
m
)
(\sqrt n +\sqrt m)
(n+m)种取值,总复杂度
O
(
n
+
T
∗
(
n
+
m
)
)
O(n+T*(\sqrt n+\sqrt m))
O(n+T∗(n+m))。代码中
D
D
D是约数个数函数。
m
u
mu
mu和
D
D
D都记的是前缀和。
#include<bits/stdc++.h>
#define re register
#define ll long long
using namespace std;
const int N=5e4+10;
int T,n,m;ll ans,D[N];
int mark[N],mu[N],num[N],P[N],cnt=0;
inline void linear_sieves(){
mark[1]=mu[1]=D[1]=1;
for(int i=2;i<N;++i){
if(!mark[i]) P[++cnt]=i,D[i]=2,num[i]=1,mu[i]=-1;
for(int j=1;j<=cnt&&i*P[j]<N;++j){
mark[i*P[j]]=1;
if(i%P[j]) mu[i*P[j]]=-mu[i],D[i*P[j]]=D[i]*2,num[i*P[j]]=1;
else{
mu[i*P[j]]=0,num[i*P[j]]=num[i]+1;
D[i*P[j]]=D[i]/(num[i]+1)*(num[i]+2);
break;
}
}mu[i]+=mu[i-1],D[i]+=D[i-1];
}
}
int main(){
linear_sieves(),scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m),ans=0;
for(int re d=1,nxd;d<=min(n,m);d=nxd+1)
nxd=min(n/(n/d),m/(m/d)),
ans+=(mu[nxd]-mu[d-1])*D[n/d]*D[m/d];
printf("%lld\n",ans);
}
}