题意:
定义 f(x) = { num | a*b| x } , 求 \sum { f(x) } , x <= 10^11
思路:
题目等价于求 a*b*c <= n 的数量.
假定 a <= b <= c. 则 a <= n^(1/3) , b <= n^(1/2)
所以我们可以通过枚举 a,b 计算出数量,时间复杂度未 O(n^(2/3))
对于枚举的 a, b, c; 有三种情况
1 . 三个相等 a, a, a 则只需要计算一次 ,
数量为: n^(1/3)
2. 二个相等, a, a, b or a, b, b 则需要计算 C(1,3) = 3 次
数量为: n/(a*a) - a and (n/a)^(1/2) - a
3. 三个都不相等 a, b, c , 则方案数为 P(3,3) = 6 次
数量为: n/(a*b) - b
定义 f(x) = { num | a*b| x } , 求 \sum { f(x) } , x <= 10^11
思路:
题目等价于求 a*b*c <= n 的数量.
假定 a <= b <= c. 则 a <= n^(1/3) , b <= n^(1/2)
所以我们可以通过枚举 a,b 计算出数量,时间复杂度未 O(n^(2/3))
对于枚举的 a, b, c; 有三种情况
1 . 三个相等 a, a, a 则只需要计算一次 ,
数量为: n^(1/3)
2. 二个相等, a, a, b or a, b, b 则需要计算 C(1,3) = 3 次
数量为: n/(a*a) - a and (n/a)^(1/2) - a
3. 三个都不相等 a, b, c , 则方案数为 P(3,3) = 6 次
数量为: n/(a*b) - b
另外要注意的是, 直接用pow(n,m) 求得的值会 四舍五入.要注意 保证 m*m <= n or m*m*m <= n 中最大的m
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
__int64 n,m,t,ni,ans,i,j,k;
__int64 pow3(__int64 a)//比a的立方根小的最大的整数
{
__int64 b=pow(a,1.0/3);
//cout<<b<<endl;
while(b*b*b<a) b++;
while(b*b*b>a) b--;
return b;
}
__int64 pow2(__int64 a)
{
__int64 b=pow(a,0.5);
while(b*b<a) b++;
while(b*b>a) b--;
return b;
}
int main()
{
t=0;
while(~scanf("%I64d",&n))
{
t++;
ans=0;
m=pow3(n);//i*j*z<=n 其中i<=j<=z 所以i的最大值是m
// cout<<m<<endl;
ans+=m;//第一种情况 i*i*i<=n
for(i=1;i<=m;i++)
{
ni=n/i;//第二种情况:1、j*j<=n/i 2、j<=n/i*i
k=pow2(ni);//由上式知 i<=j<=k 得到i j的范围
ans+=(ni/i+k-2*i)*3;//上面1、得到ans=k-(i+1)-1、因为j>i(取=就跟第一种情况相同了) 所以j从i+1取到k该等式都成立 同理得2\ans=ni/i-i
for(j=i+1;j<=k;j++)//第三种情况 c<=n/(i*j) ans=ni/j-j c取j+1到ni/j再减1(减去跟二重复)
ans+=(ni/j-j)*6;//因为假设是i<=j<=c 而题目没有顺序 每种情况重新排列有6种 所以*6 第二种情况*3同理
}
printf("Case %I64d: %I64d\n",t,ans);
}
return 0;
}