[bzoj3994][SDOI2015]约数个数和-数论
Brief Description
计算\(\sum_{i\leqslant n}\sum_{j\leqslant m}\sigma_0(ij)\).
Algorithm Design
首先证明一个结论
\[d(ij) = \sum_{i\leqslant n}\sum_{j \leqslant m}[(i,j)=1]
\]
我们不显式地证明它, 仅仅直观地考虑每个质数对于答案的贡献就好.
有了这个结论我们开始推式子:
\[\begin{aligned}
\sum_{i\leqslant n}\sum_{j\leqslant m}\sigma_0(ij) & = \sum_{i\leqslant n}\sum_{j\leqslant m} \sum_{a|i} \sum_{b|j} [(i,j)=1]\\ & =\sum_{i\leqslant n}\sum_{j\leqslant m}\sum_{a|i}\sum_{b|j}\sum_{x|(i,j)}\mu(x)\\& =\sum_{i\leqslant n}\sum_{j \leqslant m}\sum_{x|i+j}\mu(x)\sigma_0(\frac ix)\sigma_0(\frac jx) \\ &=\sum_{x \leqslant n} \mu(x)\sum_{i \leqslant \lfloor \frac nx \rfloor} \sigma_0(i)\sum_{j \leqslant \lfloor \frac mx \rfloor}\sigma_0(j)
\end{aligned}
\]
有了最后的式子, 我们就可以开始乱搞了.
复杂度\(O(n+T\sqrt n)\)
Code
#include <algorithm>
#include <cctype>
#include <cstdio>
#define ll long long
const int maxn = 50000 + 10;
int prime[maxn], tot;
int mu[maxn], sigma[maxn], summu[maxn];
ll sumsigma[maxn];
bool check[maxn];
int read() {
int x = 0, f = 1;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-')
f = -1;
ch = getchar();
}
while (isdigit(ch)) {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
void shake() {
int minPrimeCnt[maxn];
mu[1] = 1, sigma[1] = 1;
for (int i = 2; i < maxn; i++) {
if (!check[i]) {
prime[tot++] = i;
mu[i] = -1;
sigma[i] = 2;
minPrimeCnt[i] = 1;
}
for (int j = 0; j < tot; j++) {
int x = i * prime[j];
if (x >= maxn)
break;
check[x] = 1;
if (i % prime[j] == 0) {
mu[x] = 0;
minPrimeCnt[x] = minPrimeCnt[i] + 1;
sigma[x] = sigma[i] / (minPrimeCnt[i] + 1) * (minPrimeCnt[x] + 1);
break;
} else {
mu[x] = -mu[i];
sigma[x] = sigma[i] << 1;
minPrimeCnt[x] = 1;
}
}
}
summu[0] = 0;
for (int i = 1; i < maxn; i++)
summu[i] = summu[i - 1] + mu[i];
for (int i = 1; i < maxn; i++)
sumsigma[i] = sumsigma[i - 1] + sigma[i];
}
ll F(int n, int m) {
if (n > m)
std::swap(n, m);
ll ans = 0;
for (int i = 1, last = 1; i <= n; i = last + 1) {
last = std::min(n / (n / i), m / (m / i));
ans += (summu[last] - summu[i - 1]) * sumsigma[n / i] * sumsigma[m / i];
}
return ans;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input", "r", stdin);
#endif
shake();
int kase = read();
while (kase--) {
int n = read(), m = read();
printf("%lld\n", F(n, m));
}
return 0;
}