题目描述
设d(x)为x的约数个数,给定N、M,求 ∑ i = 1 n ∑ j = 1 m d ( i j ) \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}d(ij) i=1∑nj=1∑md(ij)
输入格式
输入文件包含多组测试数据。第一行,一个整数T,表示测试数据的组数。接下来的T行,每行两个整数N、M。
输出格式
T行,每行一个整数,表示你所求的答案。
输入输出样例
输入 #1
2
7 4
5 6
输出 #1
110
121
说明/提示
1<=N, M<=50000
1<=T<=50000
分析
首先有一个结论(别看我我不会证
d
(
i
j
)
=
∑
x
∣
i
∑
y
∣
j
[
g
c
d
(
x
,
y
)
=
=
1
]
d(ij) =\sum\limits_{x|i}\sum\limits_{y|j}[gcd(x,y)==1]
d(ij)=x∣i∑y∣j∑[gcd(x,y)==1]
于是
a
n
s
=
∑
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
]
=
∑
i
=
1
n
∑
j
=
1
m
∑
x
∣
i
∑
y
∣
j
∑
k
∣
x
,
k
∣
y
μ
(
k
)
=
∑
k
=
1
n
μ
(
k
)
∑
i
=
1
⌊
n
k
⌋
⌊
n
k
d
⌋
∑
j
=
1
⌊
m
k
⌋
⌊
m
k
j
⌋
ans = \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}d(ij)= \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\sum\limits_{x|i}\sum\limits_{y|j}[gcd(x,y)==1]=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\sum\limits_{x|i}\sum\limits_{y|j}\sum\limits_{k|x,k|y}\mu(k)=\sum\limits_{k=1}^{n}\mu(k)\sum\limits_{i=1}^{{\tiny\left\lfloor\dfrac{n}{k}\right\rfloor}}\left\lfloor\dfrac{n}{kd}\right\rfloor\sum\limits_{j=1}^{{\tiny\left\lfloor\dfrac{m}{k}\right\rfloor}}\left\lfloor\dfrac{m}{kj}\right\rfloor
ans=i=1∑nj=1∑md(ij)=i=1∑nj=1∑mx∣i∑y∣j∑[gcd(x,y)==1]=i=1∑nj=1∑mx∣i∑y∣j∑k∣x,k∣y∑μ(k)=k=1∑nμ(k)i=1∑⌊kn⌋⌊kdn⌋j=1∑⌊km⌋⌊kjm⌋
记
g
(
n
)
=
∑
i
=
1
n
⌊
n
i
⌋
g(n) = \sum\limits_{i=1}^{n}\left\lfloor\dfrac{n}{i}\right\rfloor
g(n)=i=1∑n⌊in⌋,于是
a
n
s
=
∑
k
=
1
n
μ
(
k
)
∗
g
(
⌊
n
k
⌋
)
∗
g
(
⌊
m
k
⌋
)
ans = \sum\limits_{k=1}^{n}\mu(k)*g(\left\lfloor\dfrac{n}{k}\right\rfloor)*g(\left\lfloor\dfrac{m}{k}\right\rfloor)
ans=k=1∑nμ(k)∗g(⌊kn⌋)∗g(⌊km⌋),除法分块即可。
总复杂度
O
(
n
n
+
T
n
)
O(n\sqrt{n}+T\sqrt{n})
O(nn+Tn)
代码如下
#include <bits/stdc++.h>
#define N 50005
#define LL long long
using namespace std;
int g[N], mu[N], s[N], x[N], p[N], cnt, maxn = 50000;
LL ans, z = 1;
int main(){
int i, j, n, m, t, l, r, T;
mu[1] = 1;
for(i = 2; i <= maxn; i++){
if(!x[i]) x[i] = 1, p[++cnt] = i, mu[i] = -1;
for(j = 1; j <= cnt; j++){
t = i * p[j];
if(t > maxn) break;
x[t] = 1;
if(i % p[j] == 0) break;
mu[t] = -mu[i];
}
}
for(i = 1; i <= maxn; i++) s[i] = s[i - 1] + mu[i];
for(i = 1; i <= maxn; i++){
for(l = 1; l <= i; l = r + 1){
r = i / (i / l);
g[i] += (r - l + 1) * (i / l);
}
}
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &m);
if(n > m) swap(n, m);
ans = 0;
for(l = 1; l <= n; l = r + 1){
r = min(n / (n / l), m / (m / l));
ans += z * (s[r] - s[l - 1]) * g[n / l] * g[m / l];
}
printf("%lld\n", ans);
}
return 0;
}