题目链接:https://vjudge.net/contest/70017#problem/G
题意:求n/1到n/n各个数的整数部分之和。
分析:n比较大,暴力肯定超时,后面发现就是一个数学规律,首先,值大于1的个数为n/2,大于2的个数为n/3,大于三的个数为n/4,以此类推,发现值为1的个数为n-n/2,值为2的个数为n/2-n/3,值为3的个数为n/3-n/4......如果一直这样枚举到值为n的情况,还是会超时,复杂度为O(n),于是分成两部分,以sqrt(n)为界线,小于sqrt(n)时,直接计算求和,大于sqrt(n)是使用规律求和,并且这两部分可以整合到一个循环。注意考虑特殊情况,若n/(sqrt(n))=sqrt(n),sqrt(n)会计算两次。
代码:
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int main(){
int t,n,cas=1;
cin>>t;
while(t--){
long long ans = 0;
cin>>n;
int m = sqrt(n);
for(int i=1;i<=m;i++){
ans+=n/i;
ans+=i*(n/i-n/(i+1));
}
if(n/m==m) ans-=m;
cout<<"Case "<<cas++<<": "<<ans<<endl;
}
}