G

/**
题目: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;
}
原文地址:https://www.cnblogs.com/xiaochaoqun/p/6628891.html