题目链接:https://vjudge.net/contest/304097#problem/H
调和级数的概念: ∑ k = 1 n 1 k \sum_{k=1}^{n}\frac{1}{k} ∑k=1nk1
题目中求: ∑ k = 1 n n k \sum_{k=1}^{n}\frac{n}{k} ∑k=1nkn
正常思路:
long long H( int n ) {
long long res = 0;
for( int i = 1; i <= n; i++ )
res = res + n / i;
return res;
}
若n (1 ≤ n < 2^31),上述代码就会超时
优化过程:
-
先求出前sqrt(n)项和:即n/1+n/2+…+n/sqrt(n)
long long m=sqrt(n), ans=0; for(i=1; i<=m; i++) ans+=(n/i);
-
再求出后面所有项之和
long long m=sqrt(n), ans=0;
for(i=1; i<=m; i++)
ans+=i*(n/i-n/(i+1));
解析:在进行(2)步骤,它的每一项的值小于或者等于sqrt(n),计算值为1到sqrt(n)的项的个数,乘以其项值即可快速得到答案
举例:
n=10
sqrt(10) = 3
先求出其前三项的和为10/1+10/2+10/3,再求后面
值为1的项:个数:10/1-10/2 分别是:10/10,10/9,10/8,10/7,10/6
值为2的项:个数:10/2-10/3 分别是:10/5,10/4
值为3的项:个数:10/3-10/4 分别是:sqrt(10)
注:当n/(int)sqrt(n) == (int)sqrt(n)时,值为sqrt(n)的值会被计算2次
完整代码:
long long m=sqrt(n),ans=0;
for(i=1; i<=m; i++) {
ans+=(n/i);
ans+=i*(n/i-n/(i+1));
}
i--;
if(n/i==m)
ans-=m;
未来是否繁花似锦,源自我们当下的努力