/** 题目:G - Harmonic Number (II) 链接:https://vjudge.net/contest/154246#problem/G 题意:给定一个数n,求n除以1~n这n个数的和。n达到2^31 - 1; 思路: 首先我们观察一下数据范围,2^31次方有点大,暴力会超时,所以我们看看有没有啥规律,假设 tmp 是 n/i 的值,当n == 10的时候(取具体值) 当 tmp = 1 时,个数 是10/1 - 10/2 == 5个 当 tmp = 2 时,个数 是10/2 - 10/3 == 2个 当 tmp = 3 时,个数 是10/3 - 10/4 == 1个 ………… 当 tmp = 10时,个数是10/10 - 10/11 == 1个 所以我们发现有个规律了,当tmp == i 的时候,我们要求的个数就是 10/i - 10/(i+1),然后我们前1 — sqrt(n)个数的数值还是比较大的,但是数据范围变小了 暴力可以求出来,剩下的 sqrt(n)+1 — n个数中 数据范围还是比较大,但是 n/i 的数据范围介于 1 - sqrt(n)之间,所以用我们找出的规律可以求出来,我们只需要 两个for循环就搞定了,时间复杂度 O(sqrt(n)),完全可以,剩下的就是编写程序了 自己手写就明白了。 自己没做出来了,我原先想法: 我简单测试了一下,不同的n/i没有多少。很多结果相同,是连续的。 于是二分,每一次处理一段相同N/i的区间。一段一段区间处理。然而超时了。 ac做法参考来源:https://yq.aliyun.com/articles/15323 */ #include<bits/stdc++.h> using namespace std; typedef long long ll; int main() { //init(); int T, cas=1, n; cin>>T; while(T--) { scanf("%d",&n); ll res = 0; int m = sqrt(n); for(int i = 1; i <= m; i++){ res += n/i; } for(int i = 1; i <= m; i++){ res += (n/i-n/(i+1))*i; } if(n/m==m){ res -= m; } printf("Case %d: %lld ",cas++,res); } return 0; }