Contents
Problem
Solution
1 | F(n): {裡面元素的最小公倍數是 n} |
去加總每個 MSLCM(i) 的 set 中出現的數字,像是 2 會在 F(2)、F(4)、F(6)、F(8)、F(10) 中出現(n = 10)。
依次去相加到 n 即可,記得減掉一開始的 1。
Ans: (1 + 2) + (1 + 3) + (1 + 2 + 4) + … + (1 + 2 + 5 + 10)
$\sum_{i=2}^n {MSLCM(i)} =$
$\sum_{i=1}^n{(i\times\lfloor{ \frac{n}{i} }\rfloor)} - 1$
(直接同一行打兩個 \sum 一直出錯是怎麼…)
而直接計算出每個數字的出現次數可以更快算出答案,例如 n = 10,2 的出現次數就是 $\lfloor{\frac{10}{2}}\rfloor = 5$,
3 的則是: $\lfloor{\frac{10}{3}}\rfloor = 3$。
最重要的是會有哪些數字出現次數會是一樣的,
$\lfloor{\frac{10}{6}}\rfloor = \lfloor{\frac{10}{7}}\rfloor = \lfloor{\frac{10}{8}}\rfloor = \lfloor{\frac{10}{9}}\rfloor =\lfloor{\frac{10}{10}}\rfloor = 1$
times * ((L + R) * (R - L + 1) / 2)
=> 5 * ((6 + 10) * (10 - 6 + 1) / 2)
用二分的方法去找,以 i = 1 ~ 10 來說各數字依序出現的次數是:10, 5, 3, 2, 2, 1, 1, 1, 1, 1。
Code
1 |
|
二分加速1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
inline int read()
{
int n = 0;
char c;
while ((c = getchar()) >= '0' && c <= '9')
n = n * 10 + c - '0';
return n;
}
int main()
{
int n;
while ((n = read()) != 0)
{
//i = 1 ~ n
long long ans = 0, times, R, L = 1;
while (L <= n)
{
times = n / L;
R = n / times;
ans += times * ((L + R) * (R - L + 1) / 2);
L = R + 1;
}
printf("%lld\n", ans - 1);
}
return 0;
}