【洛谷】P1403 [AHOI2005]约数研究(数学、枚举、暴力)

题目:https://www.luogu.org/problem/P1403

标签:数学、枚举、暴力

【思路】

数 — 约数
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 。

【代码】

  • 改进前(也可以AC!!)

用上面的结论,把约数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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值