题意:
求
∑ i = 1 n lcm ( i , n ) \sum_{i=1} ^{n} \text{lcm}(i,n) i=1∑nlcm(i,n)
分析:
法一:欧拉函数
拆一下 lcm ( i , n ) = i ⋅ n gcd ( i , n ) \text{lcm}(i,n) = \dfrac{i \cdot n}{\gcd{(i,n)}} lcm(i,n)=gcd(i,n)i⋅n 变为:
∑ i = 1 n i ⋅ n gcd ( i , n ) \sum_{i=1} ^{n} \frac{i \cdot n}{\gcd{(i,n)}} i=1∑ngcd(i,n)i⋅n
枚举 gcd ( i , n ) \gcd(i,n) gcd(i,n):
n ∑ d ∣ n ∑ i = 1 n i d [ gcd ( i , n ) = d ] n \sum_{d \mid n} \sum_{i=1} ^{n} \frac{i }{d}[\gcd{(i,n)} = d ] nd∣n∑i=1∑ndi[gcd(i,n)=d]
利用 gcd \gcd gcd 的性质:
n ∑ d ∣ n ∑ i = 1 n i d [ gcd ( i d , n d ) = 1 ] n \sum_{d \mid n} \sum_{i=1} ^{n} \frac{i }{d}[\gcd{(\frac{i}{d},\frac{n}{d})} = 1 ] nd∣n∑i=1∑ndi[gcd(di,dn)=1]
把 d d d 拿到上界
n ∑ d ∣ n ∑ i = 1 ⌊ n d ⌋ i [ gcd ( i , n d ) = 1 ] n \sum_{d \mid n} \sum_{i=1} ^{ \lfloor \frac{n}{d} \rfloor } i[\gcd{(i,\frac{n}{d})} = 1 ] nd∣n∑i=1∑⌊dn⌋i[gcd(i,dn)=1]
⌊ n d ⌋ \lfloor \dfrac{n}{d} \rfloor ⌊dn⌋ 等价于 d d d
n ∑ d ∣ n ∑ i = 1 d i [ gcd ( i , d ) = 1 ] n \sum_{d \mid n} \sum_{i=1} ^{ d } i[\gcd{(i,d)} = 1 ] nd∣n∑i=1∑di[gcd(i,d)=1]
由于 gcd ( i , d ) = gcd ( d − i , d ) \gcd(i, d) = \gcd(d - i,d) gcd(i,d)=gcd(d−i,d) ,所以因子必成对出现(除了1),那么总共出现了 φ ( d ) 2 \dfrac{\varphi(d)}{2} 2φ(d) 次, d − i + i = d d - i + i =d d−i+i=d,所以就是
n ∑ d ∣ n φ ( d ) 2 d n \sum_{d \mid n} \frac{\varphi(d)}{2} d nd∣n∑2φ(d)d
这样时间复杂度是 O ( N + T n ) O(N+T\sqrt{n}) O(N+Tn),但是可以用狄利克雷卷积优化,可以做到 O ( N log N + T ) O(N \log{N} + T) O(NlogN+T)
设 F ( x ) = x ⋅ φ ( x ) 2 F(x) = \dfrac{x \cdot \varphi(x)}{2} F(x)=2x⋅φ(x)
则答案为 n ⋅ F ∗ 1 n \cdot F * \textbf{1} n⋅F∗1,注意处理 d = 1 d=1 d=1 的情况。
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 5;
int T, n, primes[N], euler[N], cnt, res, f[N];
bool st[N];
void get_eulers(int n) {
euler[1] = 1;
for (int i = 2; i <= n; i ++) {
if (!st[i]) {
primes[cnt ++] = i;
euler[i] = i - 1;
}
for (int j = 0; primes[j] <= n / i; j ++) {
int t = primes[j] * i;
st[t] = 1;
if (i % primes[j] == 0) {
euler[t] = primes[j] * euler[i];
break;
}
euler[t] = (primes[j] - 1) * euler[i];
}
}
for (int i = 1; i <= n; i ++) {
for (int j = i; j <= n; j += i) {
f[j] += (euler[i] * i + 1) / 2;
}
}
}
signed main() {
get_eulers(N - 1);
cin >> T;
while (T --) {
cin >> n;
cout << n * f[n] << endl;
}
}
法二:莫比乌斯反演
还是法一的式子,推到这一步
n ∑ d ∣ n ∑ i = 1 d i [ gcd ( i , d ) = 1 ] n \sum_{d \mid n} \sum_{i=1} ^{ d } i[\gcd{(i,d)} = 1 ] nd∣n∑i=1∑di[gcd(i,d)=1]
用单位函数替换
n ∑ d ∣ n ∑ i = 1 d i ⋅ ε ( gcd ( i , d ) ) n \sum_{d \mid n} \sum_{i=1} ^{ d } i \cdot \varepsilon (\gcd{(i,d)}) nd∣n∑i=1∑di⋅ε(gcd(i,d))
莫比乌斯反演
n ∑ d ∣ n ∑ i = 1 d i ∑ k ∣ gcd ( i , d ) μ ( k ) n \sum_{d \mid n} \sum_{i=1} ^{ d } i \sum_{k \mid \gcd(i,d) } \mu(k) nd∣n∑i=1∑dik∣gcd(i,d)∑μ(k)
交换枚举次序
n ∑ d ∣ n ∑ k ∣ d k μ ( k ) ∑ i = 1 ⌊ d k ⌋ i n \sum_{d \mid n} \sum _{k \mid d} k\mu(k) \sum_{i=1} ^{ \lfloor \frac{d}{k} \rfloor } i nd∣n∑k∣d∑kμ(k)i=1∑⌊kd⌋i
对后半部分求和
n 2 ∑ d ∣ n ∑ k ∣ d k μ ( k ) ( ⌊ d k ⌋ 2 + ⌊ d k ⌋ ) \frac{n}{2} \sum_{d \mid n} \sum _{k \mid d} k\mu(k) (\lfloor \frac{d}{k} \rfloor ^ 2 + \lfloor \frac{d}{k} \rfloor) 2nd∣n∑k∣d∑kμ(k)(⌊kd⌋2+⌊kd⌋)
可以用狄利克雷卷积优化到 O ( N log N + T ) O(N\log N +T) O(NlogN+T)
设 f ( x ) = x ⋅ μ ( x ) f(x)=x \cdot \mu(x) f(x)=x⋅μ(x) , g ( x ) = x 2 + x g(x)=x^2+x g(x)=x2+x, F ( x ) = f ∗ g F(x) = f * g F(x)=f∗g
那么答案就为:
n 2 ⋅ F ∗ 1 \frac{n}{2} \cdot F * \textbf {1} 2n⋅F∗1
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 5;
int T, n, mobius[N], primes[N], cnt, F[N], ans[N];
bool st[N];
void get_mobius(int n) {
mobius[1] = 1;
for (int i = 2; i <= n; i ++) {
if (!st[i]) {
primes[cnt ++] = i;
mobius[i] = -1;
}
for (int j = 0; primes[j] * i <= n; j ++) {
int t = primes[j] * i;
st[t] = 1;
if (i % primes[j] == 0) {
mobius[t] = 0;
break;
}
mobius[t] = -mobius[i];
}
}
for (int i = 1; i <= n; i ++) {
for (int j = i; j <= n; j += i) {
F[j] += i * mobius[i] * ((j / i) * (j / i) + (j / i));
}
}
for (int i = 1; i <= n; i ++) {
for (int j = i; j <= n; j += i) {
ans[j] += F[i];
}
}
}
signed main() {
get_mobius(N - 1);
cin >> T;
while (T --) {
cin >> n;
cout << n * ans[n] / 2 << endl;
}
}