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

FZU - 2191 完美的数字

2017-08-10 21:07 411 查看

 Problem 2191 完美的数字

Accept: 551    Submit: 2035

Time Limit: 1000 mSec    Memory Limit : 32768 KB



 Problem Description

Bob是个很喜欢数字的孩子,现在他正在研究一个与数字相关的题目,我们知道一个数字的完美度是 把这个数字分解成三个整数相乘A*A*B(0<A<=B)的方法数,例如数字80可以分解成1*1*80,2*2*20 ,4*4*5,所以80的完美度是3;数字5只有一种分解方法1*1*5,所以完美度是1,假设数字x的完美度为d(x),现在给定a,b(a<=b),请你帮Bob求出

S,S表示的是从a到b的所有数字的流行度之和,即S=d(a)+d(a+1)+…+d(b)。



 Input

输入两个整数a,b(1<=a<=b<=10^15)



 Output

输出一个整数,表示从a到b的所有数字流行度之和。



 Sample Input

1 80



 Sample Output

107



 Source

福州大学第十二届程序设计竞赛

题意:每个数字都可以拆分成 A*A*B (A<=B) 的形式,而且有时候这种拆分方式不止一种 ,且规定这种拆分方式的数量为该数的完美度。现在给定两个数 a,b (a<=b) 求a,b之间(包括a,b)所有数字的完美度。

思路一:正向求解 完全暴力。一个循环遍历 [a,b] 对其中每个数分别求完美度

代码:

#include <stdio.h>
#include <math.h>
#include <iostream>
#define ll long long
using namespace std;
ll fd(ll x)
{
ll i;
ll sum=0;
double tmp;
for(i=1;i*i<=x;i++)
{
tmp=x*1.0/(i*i);
if(tmp==(ll)tmp&&(ll)tmp>=i)
sum++;
}
return sum;
}

int main()
{
ll a,b,sum;
while(~scanf("%lld %lld",&a,&b))
{
sum=0;
for(int i=a;i<=b;i++)
{
sum+=fd(i);
}
printf("%lld\n",sum);
}
return 0;
}
但是,最终提交结果显示 Time Limit Exceed这种解法还是太暴力了。

思路二:反向求解,提速。在求每一个数字x的完美度时,是将A从1遍历至sqrt(x,1/3.0),若求得的B=x/(A*A)为整数则完美度+1;

现在反向求,将A和B遍历,求出 A B 在不同情况的组合下对应是数字。当 A 取值范围从1到sqrt(x,1/3.0),

B取值范围从1到x/(A*A)时,A*A*B的取值范围则是从
1到 x。随机举些例子找规律:

x=200,
A=5,B<=200/(5*5)=8

5*5*1=25

5*5*2=50

5*5*3=75

5*5*4=100

5*5*5=125

5*5*6=150

5*5*7=175

5*5*8=200

由于A<=B 则前面 B=1,2,3,4的情况得舍去

x=100, A=4,B<=100/(4*4)=6

4*4*1=16

4*4*2=32

4*4*3=48

4*4*4=64

4*4*5=80

4*4*6=96

由于A<=B 则前面 B=1,2,3的情况得舍去
由上述可以总结 A在[1,sqrt(x,1/3.0)]区间上变化时,每次A*A*B合法的组合有x/(A*A)-A+1


由于此方法求得的总数为 [1,x]上的总完美度,题目要求是 [a,b]的总完美度,所以可以分别求 [1,b]和[1,a-1]上的总完美度,然后作差。
代码:

#include <stdio.h>
#include <math.h>
#include <iostream>
#define ll long long
using namespace std;
ll fd(ll x)
{
ll i,sq = pow(x,1/3.0);
ll sum=0;
for(i=1;i<=sq;i++)
{
sum+=x/(i*i)-i+1;
}
return sum;
}

int main()
{
ll a,b,sum;
while(~scanf("%I64d %I64d",&a,&b))
{
sum=0;
sum=fd(b)-fd(a-1);
printf("%I64d\n",sum);
}
return 0;
}

注意:题目有一个坑点 就是不支持%lld 输出 long long 必须使用%I64d
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  FZU C++