Problem Description
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)
思路:
显然暴力肯定会超时,所以肯定是找规律,然而我最讨厌这种类型的题。所以就参考了别人的博客
核心:
n/i=1的个数 n/1 - n/2
n/i=2的个数 n/2 - n/3
以此类推。
我们就可以暴力求1-sqrt(n)的n/i的值。同时求出1的个数,2的个数。当n/sqrt(n) == sqrt(n)的时候,sqrt(n)就被重复计算了,例如17/4 = 4.那么4被计算了两次。所以得减去一次的值。例如 8 就没有被重复计算。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int T, n, Case = 1;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
int m = sqrt(n);
if(m * m > n) m--;
long long ans = 0;
long long i;
for(i = 1; i <= m; i++)
{
ans += n / i;
ans += (n/i - n/(i + 1)) * i;
}
i--;
if(n / i == i) ans -= i;// n/i 加了一次,(n/i - n/(i + 1)) * i 也加了一次。
printf("Case %d: %lld\n", Case++, ans);
}
return 0;
}
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main()
{
int T, n, Case = 1;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
ll ans = 0;
ll i;
for(i = 1; i <= n;)
{
ll t = n/i;
ll num = n/t-n/(t+1);// n/i 的个数
ans += t*num;
i += num;// 跳出 n/i = t 的范围
}
printf("Case %d: %lld\n", Case++, ans);
}
return 0;
}
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main()
{
int T, n, Case = 1;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
ll ans = 0;
ll i, r;
for(i = 1; i <= n; i = r+1)
{
r = n/(n/i);// n/i 的边界,r-i+1 = n/i 出现次数 = n/(n/i) - n/(n/i+1),i = n/(n/i+1)+1,r = n/(n/i)
ans += n/i*(r-i+1);//(r-i+1) 为 n/i 出现的次数
}
printf("Case %d: %lld\n", Case++, ans);
}
return 0;
}