标签:数学、枚举、暴力
【思路】
数 — 约数
1 — 1
2 — 1,2
3 — 1,3
4 — 1,2,4
5 — 1,5
6 — 1,2,3,6
我们可以发现,在数1~6的全部约数中“1”出现的次数为(6/1)=6次;“2”出现的次数为(6/2)=3次;“3”出现的次数为(6/3)=2次;“4”出现的次数为(6/4)=1次;“5”出现的次数为(6/5)=1次;“6”出现的次数为(6/6)=1次。(注意:结果向下取整)
所以我们有结论:在数1~n中,约数i(i的取值为1到n)出现次数为 n/i 。
【代码】
用上面的结论,把约数1到n的出现次数遍历一次累加,时间复杂度为 O ( n ) O(n) O(n)。
#include <iostream>
using namespace std;
int main() {
int n, result = 0;
cin >> n;
for (int i = 1; i <= n; i++) {
result += n / i;
}
cout << result << endl;
return 0;
}
我们发现在计算出现次数 n/i 时有很多是相同的,可以通过 n / (n / i) 求出重复的最后一个 n/i 出现位置,再通过 (j - i + 1)*(n / i) 计算得出当前重复的所有值。
n/i 大概有 n \sqrt{n} n 种取值,所以时间复杂度为 O ( n ) O(\sqrt{n}) O(n)。
#include <iostream>
using namespace std;
int main() {
int n, j, result = 0;
cin >> n;
for (int i = 1; i <= n; i = j + 1) {
j = n / (n / i);
result += (j - i + 1)*(n / i);
}
cout << result << endl;
return 0;
}