hdu4473Exam

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值