\(\text{lcm}\) 不好处理,转化为 \(\gcd\):
\[n \sum_{i = 1}^n \frac{i}{\gcd(i, n)} \]\(\gcd\) 相关题目的套路——枚举因数:
\[n \sum_{d | n} \sum_{i = 1}^n \frac id [\gcd(\frac id, \frac nd) = 1] \]整理:
\[n \sum_{d | n} \sum_{i = 1}^{\frac nd} i[\gcd(i, \frac nd) = 1] \]因为枚举了 \(n\) 的每个因数 \(d\),所以 \(\dfrac nd \iff d\):
\[n \sum_{d | n} \sum_{i = 1}^{d} i[\gcd(i, d) = 1] \]考虑 \(\sum\limits_{i = 1}^d i[\gcd(i, d) = 1]\) 的求解。
已知满足条件的 \(i\) 有 \(\varphi(d)\) 个,受等差数列求和公式的启发,考虑将满足条件的 \(i\) 两两配对,使得每对的和是定值。
若 \(\gcd(i, d) = 1\),则一定有 \(\gcd(d - i, d) = 1\)。
证明:
设 \(\gcd(d - i, d) = k\),令 \(d - i = xk, d = yk, i = (y - x)k\),易得 \(\gcd(x, y) = 1\),进一步可以得到 \(\gcd(y, y - x) = 1\)。
两边同时乘上 \(k\),得 \(\gcd((y - x)k, yk) = k\),而 \(\gcd((y - x)k, yk) = \gcd(i, d) = 1\),所以 \(k = 1\),即 \(\gcd(d, i - d) = 1\)。
故 \(\sum\limits_{i = 1}^d i[\gcd(i, d) = 1] = \dfrac{\varphi(d) \times d}2\)。
特别地,\(d = 1\) 时,不存在满足上述条件的 \((i, d - i)\),此时 \(\sum\limits_{i = 1}^d i[\gcd(i, d) = 1] = 1\),直接累加进答案即可。
最后:
令 \(f(d) = \left\{ \begin{aligned} 1&, d = 1 \\ \frac{\varphi(d)}{2} \times d&, otherwise. \end{aligned} \right.\),则有:
\[ans = n \sum_{d | n} f(d) \]时间复杂度 \(O(n + T \sqrt n)\)。
代码:
#include <bits/stdc++.h>
#define MAXN 1000100
using namespace std;
typedef long long ll;
int T, n, phi[MAXN];
int cnt, prime[MAXN];
bool vis[MAXN];
template<typename _T>
void read(_T &_x) {
_x = 0;
_T _f = 1;
char _ch = getchar();
while (_ch < '0' || '9' < _ch) {
if (_ch == '-') _f = -1;
_ch = getchar();
}
while ('0' <= _ch && _ch <= '9') {
_x = (_x << 3) + (_x << 1) + (_ch & 15);
_ch = getchar();
}
_x *= _f;
}
template<typename _T>
void write(_T _x) {
if (_x < 0) {
putchar('-');
_x = -_x;
}
if (_x > 9) write(_x / 10);
putchar('0' + _x % 10);
}
void getphi(int n) {
phi[1] = 1;
for (int i = 2; i <= n; i++) {
if (!vis[i]) {
phi[i] = i - 1;
prime[++cnt] = i;
}
for (int j = 1; j <= cnt && i * prime[j] <= n; j++) {
vis[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]];
}
}
}
ll f(int d) {
if (d == 1) return 1;
return (1ll * d * phi[d]) >> 1;
}
int main() {
getphi(1e6);
read(T);
while (T--) {
read(n);
ll ans = 0;
for (int i = 1; i * i <= n; i++) {
if (n % i) continue;
ans += f(i);
if (i * i == n) break;
ans += f(n / i);
}
write(ans * n), putchar('\n');
}
return 0;
}
标签:ch,洛谷,gcd,int,nd,sum,P1891,frac,LCM
From: https://www.cnblogs.com/chy12321/p/16941788.html