疯狂 LCM(LCM SUM) - 题解
线性筛见分割线以下。
题目回顾:
有 T T T 组数据,对于每组数据,给定整数 n n n,计算:
∑ i = 1 n lcm ( i , n ) \sum_{i=1}^n \operatorname{lcm}(i, n) i=1∑nlcm(i,n)
数据保证 1 ≤ T ≤ 3 × 1 0 5 1 \le T \le 3 \times 10^5 1≤T≤3×105, 1 ≤ n ≤ 1 0 6 1 \le n \le 10^6 1≤n≤106。
分析:
推式子部分
先看看能不能直接把式子抓起来算。显然这条式子不能拿来直接算(直接算意味着单次查询 O ( n ) O(n) O(n),是不能接受的),必须推一下,使得能在合适的时间复杂度下处理。
∑ i = 1 n lcm ( i , n ) = ∑ i = 1 n i n gcd ( i , n ) = n ∑ i = 1 n i gcd ( i , n ) = n ∑ d ∣ n ∑ i = 1 n i d [ gcd ( i , n ) = d ] = n ∑ d ∣ n ∑ i = 1 n d i [ gcd ( i , n d ) = 1 ] = n ∑ d ∣ n ∑ i = 1 d i [ gcd ( i , d ) = 1 ] = n ( ∑ d ∣ n d φ ( d ) 2 + 1 2 ) = n 2 ( ∑ d ∣ n d φ ( d ) + 1 ) \begin{aligned} &\sum_{i=1}^n \operatorname{lcm}(i, n)\\ =&\sum_{i=1}^n \frac{in}{\gcd(i, n)}\\ =&n\sum_{i=1}^n \frac{i}{\gcd(i, n)}\\ =&n\sum_{d\mid n} \sum_{i=1}^n \frac id [\gcd(i, n) = d]\\ =&n\sum_{d\mid n} \sum_{i=1}^{\frac nd} i [\gcd(i, \frac nd) = 1]\\ =&n\sum_{d\mid n} \sum_{i=1}^d i [\gcd(i, d) = 1]\\ =&n(\sum_{d\mid n} \frac{d \varphi(d)}2 + \frac 12)\\ =&\frac n2(\sum_{d\mid n} d\varphi(d) + 1) \end{aligned} =======i=1∑nlcm(i,n)i=1∑ngcd(i,n)inni=1∑ngcd(i,n)ind∣n∑i=1∑ndi[gcd(i,n)=d]nd∣n∑i=1∑dni[gcd(i,dn)=1]nd∣n∑i=1∑di[gcd(i,d)=1]n(d∣n∑2dφ(d)+21)2n(d∣n∑dφ(d)+1)
推到这里就够了,有些细节需要解释一下。两个 Q&A 对应着两个难点。
Q: 倒数第三步怎么来的,为什么突然从
n
/
d
n/d
n/d 跳跃到
d
d
d 去了?
A: 我们枚举
d
d
d 和枚举
n
/
d
n/d
n/d 等价,实际上都是在找
n
n
n 的约数。
Q: 我知道
∑
i
=
1
d
i
[
gcd
(
i
,
d
)
=
1
]
\sum_{i=1}^d i [\gcd(i, d) = 1]
∑i=1di[gcd(i,d)=1] 的意义是求与
d
d
d 互质的数之和,之前学过它等于
d
φ
(
d
)
/
2
d\varphi(d)/2
dφ(d)/2,为什么后面还要加一个
1
/
2
1/2
1/2?
A: 别忘了,那个结论里面
1
1
1 是个例外。它的约数个数和显然是
1
1
1,但是按公式算得到了
1
/
2
1/2
1/2。然后不管算哪一个
n
n
n,统计的时候都会统计
d
=
1
d = 1
d=1,都会漏了
1
1
1 的另外一半
1
/
2
1/2
1/2,把它补上去就行了。
假设 f ( n ) = ∑ d ∣ n d φ ( d ) f(n) = \sum_{d\mid n} d\varphi(d) f(n)=∑d∣ndφ(d),所求就是 n ( f ( n ) + 1 ) / 2 n(f(n) + 1)/2 n(f(n)+1)/2,如果预处理 f ( n ) f(n) f(n) 的值,就可以在 O ( 1 ) O(1) O(1) 的时间复杂度下解决问题。
线性筛部分
观察, n φ ( n ) n\varphi(n) nφ(n) 可以看作 i d ( n ) id(n) id(n) 和 φ ( n ) \varphi(n) φ(n) 的积,根据积性函数的定义,我们容易知道两个积性函数的积是积性函数。
继续观察, f ( n ) f(n) f(n) 可以看作 n φ ( n ) n\varphi(n) nφ(n) 和 1 ( n ) 1(n) 1(n) 两个积性函数的狄利克雷卷积,那么 f ( n ) f(n) f(n) 就是积性函数。我们知道,只要是积性函数,就一定可以用 线性筛 在 O ( n ) O(n) O(n) 的时间复杂度下进行预处理。
显然 f ( 1 ) = 1 f(1) = 1 f(1)=1。
假设 p p p 为质数。显然 f ( p ) = 1 + p ( p − 1 ) = p 2 − p + 1 f(p) = 1 + p(p-1) = p^2 - p + 1 f(p)=1+p(p−1)=p2−p+1。
假设线性筛外层循环枚举到 i i i。若 p ∤ i p \nmid i p∤i,显然 f ( i p ) = f ( i ) f ( p ) f(ip) = f(i)f(p) f(ip)=f(i)f(p)。
关键在于解决 p ∣ i p \mid i p∣i 的情况。这是本题第三个难点。
新方案
国际金大佬曾经给出过一种方案,下面是另一种方案。截止笔者撰写此篇题解时,该方案已被较广泛使用,但尚未有人写过针对此方案的题解。现在将一步步证明出来。
先上结论: f ( i p ) = f ( i ) + p 2 ( f ( i ) − f ( i / p ) ) f(ip) = f(i) + p^2(f(i)-f(i/p)) f(ip)=f(i)+p2(f(i)−f(i/p))。
注意到:
f ( p c ) = ∑ d ∣ p c d φ ( d ) = 1 + ∑ i = 1 c p i φ ( p i ) = 1 + ∑ i = 1 c p i ⋅ p i − 1 ( p − 1 ) = 1 + ∑ i = 1 c p 2 i − p 2 i − 1 = 1 − p + p 2 − p 3 + p 4 + ⋯ − p 2 c − 1 + p 2 c = ∑ i = 0 2 c ( − p ) i \begin{aligned} &f(p^c)\\ =& \sum_{d\mid p^c} d\varphi(d)\\ =& 1 + \sum_{i=1}^c p^i\varphi(p^i)\\ =& 1 + \sum_{i=1}^c p^i \cdot p^{i-1}(p-1)\\ =& 1 + \sum_{i=1}^c p^{2i}-p^{2i-1}\\ =& 1 - p + p^2 - p^3 + p^4 + \cdots - p^{2c-1} + p^{2c}\\ =& \sum_{i=0}^{2c} (-p)^i \end{aligned} ======f(pc)d∣pc∑dφ(d)1+i=1∑cpiφ(pi)1+i=1∑cpi⋅pi−1(p−1)1+i=1∑cp2i−p2i−11−p+p2−p3+p4+⋯−p2c−1+p2ci=0∑2c(−p)i
假设 i = a ⋅ p c i = a \cdot p^c i=a⋅pc,那么 f ( i ) = f ( a ) f ( p c ) f(i) = f(a)f(p^c) f(i)=f(a)f(pc), f ( i / p ) = f ( a ) f ( p c − 1 ) f(i/p) = f(a)f(p^{c-1}) f(i/p)=f(a)f(pc−1), f ( i p ) = f ( a ) f ( p c + 1 ) f(ip) = f(a)f(p^{c+1}) f(ip)=f(a)f(pc+1)。进而得到:
f ( i p ) = f ( a ) f ( p c + 1 ) = f ( a ) ∑ i = 0 2 c + 2 ( − p ) i = f ( a ) ( ∑ i = 0 2 c ( − p ) i + ∑ i = 2 2 c + 2 ( − p ) i − ∑ i = 2 2 c ( − p ) i ) = f ( a ) ( ∑ i = 0 2 c ( − p ) i + p 2 ∑ i = 0 2 c ( − p ) i − p 2 ∑ i = 0 2 c − 2 ( − p ) i ) = f ( a ) ( f ( p c ) + p 2 f ( p c ) − p 2 f ( p c − 1 ) ) = f ( a ) f ( p c ) + p 2 ( f ( a ) f ( p c ) − f ( a ) f ( p c − 1 ) ) = f ( i ) + p 2 ( f ( i ) − f ( i / p ) ) \begin{aligned} &f(ip)\\ =& f(a)f(p^{c+1})\\ =& f(a)\sum_{i=0}^{2c+2}(-p)^i\\ =& f(a)(\sum_{i=0}^{2c}(-p)^i + \sum_{i=2}^{2c+2}(-p)^i - \sum_{i=2}^{2c}(-p)^i)\\ =& f(a)(\sum_{i=0}^{2c}(-p)^i + p^2\sum_{i=0}^{2c}(-p)^i - p^2\sum_{i=0}^{2c-2}(-p)^i)\\ =& f(a)(f(p^c) + p^2 f(p^c) - p^2 f(p^{c-1}))\\ =& f(a)f(p^c) + p^2(f(a)f(p^c)-f(a)f(p^{c-1}))\\ =& f(i) + p^2(f(i)-f(i/p)) \end{aligned} =======f(ip)f(a)f(pc+1)f(a)i=0∑2c+2(−p)if(a)(i=0∑2c(−p)i+i=2∑2c+2(−p)i−i=2∑2c(−p)i)f(a)(i=0∑2c(−p)i+p2i=0∑2c(−p)i−p2i=0∑2c−2(−p)i)f(a)(f(pc)+p2f(pc)−p2f(pc−1))f(a)f(pc)+p2(f(a)f(pc)−f(a)f(pc−1))f(i)+p2(f(i)−f(i/p))
容斥大法妙。
f ( i p ) = f ( i ) + p 2 ( f ( i ) − f ( i / p ) ) f(ip) = f(i) + p^2(f(i)-f(i/p)) f(ip)=f(i)+p2(f(i)−f(i/p)),该公式更贴合线性筛求积性函数模板,且不需要额外的改动,运行时间略优于原有方法。
代码
#include <cstdio>
#define MAXN 1000005
using namespace std;
int prime[MAXN], v[MAXN], tot;
long long f[MAXN];
void init(int n) {
f[1] = 1;
for (int i = 2; i <= n; ++i) {
if (!v[i]) {
prime[++tot] = v[i] = i;
f[i] = 1ll * i * i - i + 1;
// f[i] = i * i - i + 1; This will WA.
}
for (int j = 1; j <= tot; ++j) {
if (prime[j] > n / i) break;
v[i*prime[j]] = prime[j];
if (v[i] == prime[j]) {
f[i*prime[j]] = f[i]+(f[i]-f[i/prime[j]])*prime[j]*prime[j];
break;
} else {
f[i*prime[j]] = f[i] * f[prime[j]];
}
}
}
}
int main() {
init(MAXN - 5);
int T;
scanf("%d", &T);
while (T--) {
int n;
scanf("%d", &n);
printf("%lld\n", (f[n] + 1) * n / 2);
}
return 0;
}
CSDN 的 Markdown 做的不错,以后主要发这里了。