您的位置:首页 > 编程语言 > C语言/C++

hdu4473Exam

2013-04-26 20:23 92 查看

Exam

题意:

  定义 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

我们举例 只看第二种情况中的一种: (a,a,b)

因为我们假设a < b, 此时 a*a*b = n

则 a^2 * b = n , 那么我们通过枚举不同的 a, 就可以得出 b的取值范围,

b = [1, n / (a^2) ] , 因为要求 b > a, 所以 要减去 [1,a]这部分.

所以方案数是, n/(a^2) - a, 因为 (a,a,b) 有三种排列方式 ( a,a,b ), ( a,b,a ), (b,a,a) 所以要乘以3.

另外一种情况和 a != b != c 也是通过这样来计算.

时间复杂度在 n^(2/3) .

总的意思就是说将通过枚举a求出b的取值范围求出来为【1~b】,然后b要大于a,所以去除【1~a】这部分

// File Name: hdu4473.cpp
// Author: rudolf
// Created Time: 2013年04月26日 星期五 20时01分27秒

#include<vector>
#include<list>
#include<map>
#include<set>
#include<deque>
#include<stack>
#include<bitset>
#include<algorithm>
#include<functional>
#include<numeric>
#include<utility>
#include<sstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<ctime>
using namespace std;
typedef long long ll;
ll pow2(ll n)
{
ll m=pow(n,0.5);
while(m*m<=n)
m++;
while(m*m>n)
m--;
return m;
}
ll pow3(ll n)
{
ll m=pow(n,1.0/3);
while(m*m*m<=n)
m++;
while(m*m*m>n)
m--;
return m;
}
int main()
{
ll n;
int Case=0;
while(~scanf("%I64d",&n))
{
ll m=pow3(n);
ll ans=m;
for(int i = 1;i <= m;i++)
{
ll ni=n / i;
ll k=pow2(ni);
ans+=(ni / i + k - 2 * i) * 3;
for(int j = i + 1;j <= k; j++)
ans += (ni / j - j) * 6;
}
printf("Case %d: %I64d\n",++Case,ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  学习笔记 c++ 杭电 hut