SPOJ - DIVCNT2 Counting Divisors (square)
求 $S_{2}(n)=\sum \limits_{i=1}^n \sigma_0(i^2)$
设 $f(n)=\sigma_0(n^2)$,$g(n)=2^{\omega(n)}$,$\omega(n)$ 表示 $n$ 唯一分解后有多少个不同的质因子。
那么 $f=g *1$,即 $f(n)=\sum\limits_{d|n}2^{\omega(d)}$,考虑约数 $d^2$ 除去 $d$ 中的一个质因子集合,那么就有 $2^{\omega(d)}$ 种选法,这样能得到 $n^2$ 的所有约数。
而 $g=\mu^2 * 1$,即 $2^{\omega(n)}=\sum\limits_{d|n}\mu^2(d)$,就是 $n$ 的无平方因子约数个数。
那么 $f=g*1=\mu^2*1*1=\mu^2*\sigma_0$
那么 $S_2(n)=\sum\limits_{i=1}^n\sum\limits_{d|n}\mu^2(d)\sigma_0(\frac{i}{d})=\sum\limits_{d=1}^n \mu^2(d)\sum \limits_{i=1}^{\lfloor \frac{n}{d} \rfloor}\sigma_0(i)$
$s(n)=\sum\limits_{i=1}^n \mu^2(i)=\sum\limits_{i=1}^n \sum\limits_{d^2|i}\mu(d)=\sum\limits_{d=1}^{\sqrt n} \mu(d)\sum\limits_{i=1}^n[d^2 | i]=\sum\limits_{d=1}^{\sqrt n}\mu(d)\lfloor \frac{n}{d^2} \rfloor$,$O(\sqrt n)$ 解决。
$g(n)=\sum \limits_{i=1}^n \sigma_0(i)=\sum \limits_{d=1}^{n}\sum \limits_{d|i}1 = \sum \limits_{d=1}^{n}\lfloor \frac{n}{d} \rfloor$,$O(\sqrt n)$ 解决。
#include <bits/stdc++.h> using ll = long long; const int N = 1e8 + 7; int XN; int prime[N/10], prin; short mu[N], mn[N]; int mu2[N]; ll thi[N]; ll Q[10007]; void init() { static bool vis[N]; thi[1] = mu[1] = mu2[1] = 1; for (int i = 2; i <= XN; i++) { if (!vis[i]) { prime[++prin] = i; mu[i] = -1; thi[i] = mn[i] = 2; } for (int j = 1; j <= prin && 1LL * i * prime[j] <= XN; j++) { int v = i * prime[j]; vis[v] = 1; if (i % prime[j] == 0) { mu[v] = 0; mn[v] = mn[i] + 1; thi[v] = thi[i] / mn[i] * mn[v]; break; } mn[v] = 2; mu[v] = -mu[i]; thi[v] = 2 * thi[i]; } } for (int i = 1; i <= XN; i++) mu2[i] = mu[i] * mu[i] + mu2[i - 1], thi[i] += thi[i - 1]; } std::unordered_map<ll, ll> mpg, mps; ll g(ll n) { if (n <= XN) return mu2[n]; if (mpg.count(n)) return mpg[n]; ll ans = 0; for (int i = 1, sqr = sqrt(n); i <= sqr; i++) ans += mu[i] * (n / (1LL * i * i)); return mpg[n] = ans; } ll s(ll n) { if (n <= XN) return thi[n]; if (mps.count(n)) return mps[n]; ll ans = 0; for (ll i = 1, j; i <= n; i = j + 1) { j = n / (n / i); ans += (j - i + 1) * (n / i); } return mps[n] = ans; } int main() { int T; scanf("%d", &T); ll mx = 0; for (int i = 1; i <= T; i++) scanf("%lld", Q + i), mx = std::max(mx, Q[i]); XN = pow(mx, 2. / 3.); if (XN >= 1e6 && XN <= 1e8 + 1) XN = 1e8; init(); for (int t = 1; t <= T; t++) { ll n = Q[t]; ll ans = 0; for (ll i = 1, j; i <= n; i = j + 1) { j = n / (n / i); ans += s(n / i) * (g(j) - g(i - 1)); } printf("%lld\n", ans); } return 0; }