LG化學:正推進與通用等多家制造商成立電池合資企業
阿新 • • 發佈:2020-10-16
一個基於觀察不依賴於反演的做法。
首先 \(\rm lcm\) 是不好算的,轉化為計算 \(\rm gcd\) 的問題,求:
\[\sum\limits_{i = 1} ^ n \frac{in}{\gcd(i, n)} \]注意到 \(\gcd(n - i, n) = \gcd(i, n), (n - i) \times n + in = n ^ 2\),可以考慮將 \(\gcd(n - i, n), \gcd(i, n)\) 一起計算。
具體地,將原式乘 \(2\), 前後配對。需要注意的是會多出一項,需要額外拿出來。
\[\frac{1}{2} (\sum\limits_{i = 1} ^ n \frac{n ^ 2}{\gcd(i, n)} + n) \]按照技巧列舉 \(d = \gcd(i, n)\):
\[\frac{1}{2} (\sum\limits_{d \mid n} \sum\limits_{i = 1} ^ n \frac{n ^ 2}{d} [\gcd(i, n) = d] + n) \]後面的部分可以除去 \(d\):
\[\frac{1}{2} (\sum\limits_{d \mid n} \sum\limits_{i = 1} ^ {\frac{n}{d}} \frac{n ^ 2}{d} [\gcd(i, n) = 1] + n) \]即:
\[\frac{1}{2} (\sum\limits_{d \mid n} \frac{n ^ 2}{d} \times \varphi(\frac{n}{d}) + n) \]方便起見列舉 \(d = \frac{n}{d}\):
\[\frac{n}{2} (n \times \sum\limits_{d \mid n} \times d \varphi(d) + 1) \]中間的求和部分與 \(n\) 無關,直接列舉 \(d\) 再列舉倍數累加貢獻即可,複雜度 \(O(n \ln n + T)\)。
#include <bits/stdc++.h> using namespace std; #define int long long #define rep(i, l, r) for (int i = l; i <= r; ++i) const int N = 1000000 + 5; bool iprime[N]; int T, n, tot, phi[N], ans[N], prime[N]; int read() { char c; int x = 0, f = 1; c = getchar(); while (c > '9' || c < '0') { if(c == '-') f = -1; c = getchar();} while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } signed main() { T = read(); iprime[1] = phi[1] = 1; rep(i, 2, N - 5) { if(!iprime[i]) prime[++tot] = i, phi[i] = i - 1; for (int j = 1; j <= tot && i * prime[j] <= N - 5; ++j) { iprime[i * prime[j]] = 1; if(i % prime[j] == 0) { phi[i * prime[j]] = phi[i] * prime[j]; break;} phi[i * prime[j]] = phi[i] * phi[prime[j]]; } } rep(i, 1, N - 5) for (int j = i; j <= N - 5; j += i) ans[j] += i * phi[i]; while (T--) n = read(), printf("%lld\n", (n * ans[n] + n) / 2); return 0; }