题目描述
% 给定 n n n,求 ∑ i = 1 n ∑ j = 1 n d ( gcd ( i , j ) ) \sum_{i=1}^n\sum_{j=1}^nd(\gcd(i,j)) i=1∑nj=1∑nd(gcd(i,j))
对
1
0
9
+
7
10^9+7
109+7 取模的结果,其中
d
(
x
)
d(x)
d(x) 表示
x
x
x 的约数个数。
数据范围
1
⩽
n
⩽
1
0
12
1\leqslant n\leqslant 10^{12}
1⩽n⩽1012
题目描述
%
先枚举
x
=
gcd
(
i
,
j
)
x=\gcd(i,j)
x=gcd(i,j),然后莫比乌斯反演常规套路。
∑
i
=
1
n
∑
j
=
1
n
d
(
(
i
,
j
)
)
=
∑
x
=
1
n
∑
i
=
1
n
∑
j
=
1
n
d
(
x
)
[
(
i
,
j
)
=
x
]
=
∑
x
=
1
n
∑
i
=
1
n
x
∑
j
=
1
n
x
d
(
x
)
∑
d
∣
(
i
,
j
)
μ
(
d
)
=
∑
x
=
1
n
d
(
x
)
∑
i
=
1
n
x
∑
j
=
1
n
x
∑
d
∣
(
i
,
j
)
μ
(
d
)
=
∑
x
=
1
n
d
(
x
)
∑
d
=
1
n
μ
(
d
)
⌊
n
d
x
⌋
2
=
∑
i
=
1
n
⌊
n
i
⌋
2
∑
d
∣
i
d
(
i
d
)
μ
(
d
)
=
∑
i
=
1
n
⌊
n
i
⌋
2
(
d
∗
μ
)
(
i
)
\begin{aligned}\sum_{i=1}^n\sum_{j=1}^nd((i,j)) &=\sum_{x=1}^n\sum_{i=1}^n\sum_{j=1}^nd(x)[(i,j)=x]\\ &=\sum_{x=1}^n\sum_{i=1}^{\frac nx}\sum_{j=1}^{\frac nx}d(x)\sum_{d|(i,j)}\mu(d)\\ &=\sum_{x=1}^nd(x)\sum_{i=1}^{\frac nx}\sum_{j=1}^{\frac nx}\sum_{d|(i,j)}\mu(d)\\ &=\sum_{x=1}^nd(x)\sum_{d=1}^n\mu(d)\left\lfloor\frac n{dx}\right\rfloor^2\\ &=\sum_{i=1}^n\left\lfloor\frac n{i}\right\rfloor^2\sum_{d|i} d(\frac id)\mu(d)\\ &=\sum_{i=1}^n\left\lfloor\frac n{i}\right\rfloor^2(d*\mu)(i)\\ \end{aligned}
i=1∑nj=1∑nd((i,j))=x=1∑ni=1∑nj=1∑nd(x)[(i,j)=x]=x=1∑ni=1∑xnj=1∑xnd(x)d∣(i,j)∑μ(d)=x=1∑nd(x)i=1∑xnj=1∑xnd∣(i,j)∑μ(d)=x=1∑nd(x)d=1∑nμ(d)⌊dxn⌋2=i=1∑n⌊in⌋2d∣i∑d(di)μ(d)=i=1∑n⌊in⌋2(d∗μ)(i)
%
考虑到对于常函数
1
(
n
)
=
1
1(n)=1
1(n)=1 和单位函数
ϵ
(
n
)
=
[
n
=
1
]
\epsilon(n)=[n=1]
ϵ(n)=[n=1],有
1
∗
μ
=
ϵ
,
1
∗
1
=
d
1*\mu=\epsilon,1*1=d
1∗μ=ϵ,1∗1=d,因而
(
d
∗
μ
)
(
i
)
=
(
1
∗
1
∗
μ
)
(
i
)
=
(
1
∗
ϵ
)
(
i
)
=
1
(
i
)
=
1
(d*\mu)(i)=(1*1*\mu)(i)=(1*\epsilon)(i)=1(i)=1
(d∗μ)(i)=(1∗1∗μ)(i)=(1∗ϵ)(i)=1(i)=1
% 因此有 ∑ i = 1 n ∑ j = 1 n d ( ( i , j ) ) = ∑ i = 1 n ⌊ n i ⌋ 2 \sum_{i=1}^n\sum_{j=1}^nd((i,j))=\sum_{i=1}^n\left\lfloor\frac n{i}\right\rfloor^2 i=1∑nj=1∑nd((i,j))=i=1∑n⌊in⌋2
% 直接除法分块即可。
代码
% 由于 n n n 的范围比较大,需要注意除法分块过程中不要忘记取模。
#include<bits/stdc++.h>
using namespace std;
const long long mod=1000000007;
#define int long long
signed main(){
int n,T;
scanf("%lld",&T);
while(T--&&~scanf("%lld",&n)){
int ans=0;
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l);
ans+=((n/l)%mod)*((n/l)%mod)%mod*((r-l+1+mod)%mod)%mod;
ans%=mod;
}
printf("%lld\n",ans%mod);
}
return 0;
}