# BZOJ3994 [SDOI2015]约数个数和

## Description

设d(x)为x的约数个数，给定N、M，求$\sum_{i=1}^n\sum_{j=1}^md(ij)$

## Output

T行，每行一个整数，表示你所求的答案。

2
7 4
5 6

110
121

1<=N, M<=50000

1<=T<=50000

## Solution

$$d(ij) = \sum_{x|i}\sum_{y|j} [gcd(\frac ix, y) = 1] = \sum_{x'|i}\sum_{y|j} [gcd(x', y) = 1]$$

\begin{aligned} \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]\\ &=\sum_{x=1}^N\sum_{y=1}^M [gcd(x, y) = 1]\left\lfloor\frac Nx\right\rfloor \left\lfloor\frac My\right\rfloor \end{aligned}

\begin{aligned} \sum_{n|d}f(d) &= \sum_{x=1}^N\sum_{y=1}^M [n|gcd(x, y)]\left\lfloor\frac Nx\right\rfloor \left\lfloor\frac My\right\rfloor\\ &= \sum_{i=1}^{\left\lfloor\frac Nn\right\rfloor}\sum_{j=1}^{\left\lfloor\frac Mn\right\rfloor} \left\lfloor\frac{\left\lfloor\frac Nn\right\rfloor}i \right\rfloor\left\lfloor\frac{\left\lfloor\frac Mn\right\rfloor}j\right\rfloor \end{aligned}

$ans = f(1) = \sum_{n=1}^{min(N, M)}\mu(n)t(\left\lfloor\frac Nn\right\rfloor)t(\left\lfloor\frac Mn\right\rfloor)$

#include <algorithm>
#include <cstdio>
typedef long long LL;
const int N = 50050;
LL t[N];
LL calcT(int n) {
LL ans = 0;
for (int i = 1, last; i <= n; i = last + 1) {
last = n / (n / i);
ans += n / i * (last - i + 1);
}
return ans;
}
bool mark[N];
int pr[N], pcnt = 0, mu[N], S[N];
void getMu() {
mu[1] = 1;
for (int i = 2; i < N; ++i) {
if (!mark[i]) mu[pr[pcnt++] = i] = -1;
for (int j = 0; j < pcnt && (LL)i * pr[j] < N; ++j) {
mark[i * pr[j]] = 1;
if (!(i % pr[j])) {
mu[i * pr[j]] = 0;
break;
}
mu[i * pr[j]] = -mu[i];
}
}
for (int i = 1; i < N; ++i) S[i] = S[i - 1] + mu[i];
}
LL solve(int n, int m) {
LL ans = 0;
for (int i = 1, last; i <= n && i <= m; i = last + 1) {
last = std::min(n / (n / i), m / (m / i));
ans += t[n / i] * t[m / i] * (S[last] - S[i - 1]);
}
return ans;
}
int main() {
for (int i = 1; i < N; ++i) t[i] = calcT(i);
getMu();
int T, n, m;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m);
printf("%lld\n", solve(n, m));
}
return 0;
}


posted @ 2017-08-17 09:08  _rqy  阅读(676)  评论(0编辑  收藏  举报