给出
n
,
m
n,m
n,m,计算
∑
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)
其中
d
(
x
)
d(x)
d(x)是
x
x
x的约数个数
有一条结论
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]
那么即计算
∑
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=1∑nj=1∑mx∣i∑y∣j∑[gcd(x,y)=1]
莫比乌斯反演得到
∑
i
=
1
n
∑
j
=
1
m
∑
x
∣
i
∑
y
∣
j
∑
d
∣
g
c
d
(
x
,
y
)
μ
(
d
)
\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{x|i}\sum_{y|j}\sum_{d|gcd(x,y)}\mu(d)
i=1∑nj=1∑mx∣i∑y∣j∑d∣gcd(x,y)∑μ(d)
优先枚举因子,这里有
x
,
i
x,i
x,i是因子和因子的因子,优先枚举更因子的因子
d
d
d,这样
x
x
x就是
d
d
d的倍数,
i
i
i就是
x
x
x的倍数,
∑
d
=
1
n
μ
(
d
)
(
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
n
i
d
⌋
1
)
(
∑
i
=
1
⌊
m
d
⌋
∑
j
=
1
⌊
m
i
d
⌋
1
)
=
∑
d
=
1
n
μ
(
d
)
(
∑
i
=
1
⌊
n
d
⌋
⌊
n
i
d
⌋
)
(
∑
i
=
1
⌊
m
d
⌋
⌊
m
i
d
⌋
)
(1)
\sum_{d=1}^{n}\mu(d)(\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{id}\rfloor}1)(\sum_{i=1}^{\lfloor\frac{m}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{id}\rfloor}1)=\sum_{d=1}^{n}\mu(d)(\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\lfloor\frac{n}{id}\rfloor)(\sum_{i=1}^{\lfloor\frac{m}{d}\rfloor}\lfloor\frac{m}{id}\rfloor) \tag{1}
d=1∑nμ(d)(i=1∑⌊dn⌋j=1∑⌊idn⌋1)(i=1∑⌊dm⌋j=1∑⌊idm⌋1)=d=1∑nμ(d)(i=1∑⌊dn⌋⌊idn⌋)(i=1∑⌊dm⌋⌊idm⌋)(1)
令
f
(
x
)
=
∑
i
=
1
x
⌊
x
i
⌋
f(x)=\sum_{i=1}^{x}\lfloor\frac{x}{i}\rfloor
f(x)=i=1∑x⌊ix⌋
原式即
∑
d
=
1
n
μ
(
d
)
f
(
⌊
n
d
⌋
)
f
(
⌊
m
d
⌋
)
\sum_{d=1}^{n}\mu(d)f(\lfloor\frac{n}{d}\rfloor)f(\lfloor\frac{m}{d}\rfloor)
d=1∑nμ(d)f(⌊dn⌋)f(⌊dm⌋)
显然这个式子可以数论分块,每个
f
(
x
)
f(x)
f(x)也可以数论分块,此时总复杂度是
O
(
T
n
)
O(Tn)
O(Tn),发现每个
f
(
x
)
f(x)
f(x)可以预处理出来,那么时间复杂度就降到了
O
(
n
n
+
T
n
)
O(n\sqrt{n}+T\sqrt{n})
O(nn+Tn)
( 1 ) (1) (1)式需要注意的地方是,枚举 d d d的倍数作为 x x x, x x x的倍数作为 i i i(这里的 x , i x,i x,i都是对 ( 1 ) (1) (1)式之前而言的),一开始做的时候把 i i i看成比 x x x大的 d d d的倍数就可以了,实际上这是不一定的,比如说 x = 3 d , i = 7 d x=3d,i=7d x=3d,i=7d, x x x并不能整除 i i i,所以 ( 1 ) (1) (1)式的左式的每个括号内的第二个求和的上标发生了变化。可能是练太少了,一些细节还是难注意到
// #include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using ll=long long;
const int N=5e4+5;
int mu[N],prime[N],cnt,sum[N];
bool nt[N];
ll f[N];
ll calc(int x)
{
ll ret=0;
for(int l=1,r;l<=x;l=r+1)
{
r=x/(x/l);
ret+=x/l*(r-l+1);
}
return ret;
}
void make_prime()
{
mu[1]=1;
for(int i=2;i<=50000;i++)
{
if(!nt[i]) prime[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&i*prime[j]<=50000;j++)
{
nt[i*prime[j]]=true;
if(i%prime[j]==0) break;
else mu[i*prime[j]]=mu[i]*mu[prime[j]];
}
}
for(int i=1;i<=50000;i++)
{
sum[i]=sum[i-1]+mu[i];
f[i]=calc(i);
}
}
int main()
{
make_prime();
int t; cin>>t;
while(t--)
{
ll ans=0;
int n,m; cin>>n>>m;
if(n>m) swap(n,m);
for(int l=1,r;l<=n;l=r+1)
{
r=min(n/(n/l),m/(m/l));
ans+=f[n/l]*f[m/l]*(sum[r]-sum[l-1]);
}
printf("%lld\n",ans);
}
return 0;
}