luogu P3327 [SDOI2015]約數個數和
阿新 • • 發佈:2020-09-22
\[\begin{aligned}
\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} [(x,y)=1]\\
&=\sum\limits_{x=1}^n\sum\limits_{y=1}^m[(x,y)=1]\lfloor \frac{n}{x}\rfloor \lfloor\frac{m}{y}\rfloor\\
&=\sum\limits_{x=1}^n\sum\limits_{y=1}^m\sum\limits_{d|x,y}\mu(d)\lfloor \frac{n}{x}\rfloor \lfloor\frac{m}{y}\rfloor\\
&=\sum\limits_{d=1}^n\mu(d)\sum\limits_{x=1}^{n/d}\sum\limits_{y=1}^{m/d}\lfloor \frac{n}{xd}\rfloor \lfloor\frac{m}{yd}\rfloor\\
&=\sum\limits_{d=1}^n\mu(d)\sum\limits_{x=1}^{n/d}d(x)\sum\limits_{y=1}^{m/d}d(y)
\end{aligned}
\]
預處理函式 \(d(x),\mu(x)\) 的字首和然後整除分塊即可。
程式碼:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define int long long using namespace std; const int N = 50000; int n, m, u[N + 9], a[N + 9], p[N], cnt, d[N + 9]; void prework() { u[1] = d[1] = 1; for (int i = 2; i <= N; i++) { if (!a[i]) a[i] = i, p[++cnt] = i, u[i] = -1, d[i] = 2; for (int j = 1; j <= cnt; j++) { if (p[j] > a[i] || p[j] > N / i) break; a[p[j] * i] = p[j]; if (i % p[j] != 0) u[p[j] * i] = u[p[j]] * u[i], d[p[j] * i] = d[p[j]] * d[i]; else d[p[j] * i] = 2 * d[i] - d[i / p[j]]; } } for (int i = 1; i <= N; i++) d[i] += d[i - 1], u[i] += u[i - 1]; } signed main() { prework(); int T; scanf("%lld", &T); while (T--) { scanf("%lld %lld", &n, &m); if (n > m) swap(n, m); int ans = 0; for (int i = 1; i <= n; i++) { int k = min(n / (n / i), m / (m / i)); ans += d[n / i] * d[m / i] * (u[k] - u[i - 1]); i = k; } printf("%lld\n", ans); } }