0
点赞
收藏
分享

微信扫一扫

【牛客 - 练习】约数个数的和(数论,数学)

题干:
 

给个n,求1到n的所有数的约数个数的和~

输入描述:

第一行一个正整数n

输出描述:

输出一个整数,表示答案

示例1

输入

复制

3

输出

复制

5

说明

样例解释:
1有1个约数1
2有2个约数1,2
3有2个约数1,3

备注:

n <= 100000000

解题报告:

   看到数据范围,nlogn打表肯定是不行的,但是因为求的是所有数的约数个数和,考虑每个数约数k,1~n这些数的约数中有k的数是n/k个,所以k给答案加上n/k。

AC代码:

#include<iostream>
using namespace std;
int main()
{
int n,i,s=0;
cin>>n;
for(i=1;i<=n;i++)
s+=n/i;
cout<<s;
return 0;
}

法二:

【牛客 - 练习】约数个数的和(数论,数学)_c代码

也就是【牛客 - 练习】约数个数的和(数论,数学)_约数个数_02,所以有这个公式,至于为什么可以O(sqrt(n))求解,

有很多【牛客 - 练习】约数个数的和(数论,数学)_打表_03都是一样的 对于这些一样的数我们每次算一次 似乎很浪费时间

所以我们每次i跳到【牛客 - 练习】约数个数的和(数论,数学)_打表_04这样的j上 对于中间一样的数一次性算掉

这样的复杂度又是多少呢?打表测试一下就好了 复杂度O(2*sqrt(n)).

【牛客 - 练习】约数个数的和(数论,数学)_约数个数_05

AC代码:

#include <bits/stdc++.h>
using namespace std;
long long ans;
int main() {
int n;
scanf("%d", &n);
for (int i = 1, j; i <= n; i = j + 1) {
j = min(n, n / (n / i));
ans += (long long)(j - i + 1) * (n / i);
}
printf("%lld\n", ans);
return 0;
}

对于O(sqrt(n))的算法还有另一种解释:


举报

相关推荐

0 条评论