小数化分数
Problem Description
将给出的小数化为分数
Input
只有一行,为要转换的小数(正负均有)。
注意:小数的格式有好几种。为了方便起见,循环部分均被括号括起来了。
有前导0或后导0的例子:09.400(输出47/5)
纯循环小数的例子:0.(3)(输出1/3)
混循环小数的例子:0.5(142857)(输出18/35)
输入数据都是正确的,不用判错。保证如果有循环节,那么输入的最后一个字符必然是右括号;如果有前导0,一定是正数。
Output
只有一行,为非带分数(也就是说只有真分数或假分数)的形式。
注意分数线一定为左斜杠。
Sample Input 1:
09.400
Sample Output 1:
47/5
Sample Input 2:
0.(3)
Sample Output 2:
1/3
Sample Input 3:
0.5(142857)
Sample Output 3:
18/35
Tip
题目大意:给定一个(可能有整数部分、有可能有前导0和后导0、有可能是纯循环或混循环或不循环)的小数,求出其非带分数(也就是说只有真分数或假分数)表示形式。
要注意的是,1.(9)、1.9(9)和4/2都表示2这个数字。
DataInstraint
100%保证运算过程中及输出结果的值不会超过2^(64-1)。
观察本题,容易发现,此题目要求我们将所给小数化成分数。
对于题目所给小数的读入各显神通,在这里不再多说。
一开始,我们的思路是,假定分数a/b,使其逼近题目所给的值,并且根据其与题目所给小数的大小比较,逐次增加a或b的值,来使其逼近题目所给小数。
不过,这种方法其本身正确性便值得推敲,二来时间消耗大,故不为所取。
所以,我们继续观察本题。经过猜想、推测、验证,很容易知道,对于一个循环的数0.(x),它化成分数的形式应该是 x/99……99 (9的个数就是x的位数)
那么,我们通过这个东西,就可以快速的将小数部分的分母分子求出,进行通分约分,得到最后答案。
当然,要注意的是,由于数据较大,通分过程要讲究顺序,以免运算出现过大的数。
代码如下。
#include <cstdio>
typedef long long LL;
using namespace std;
LL a=0,b=1,la=0,lb=0,x=0;
LL num;
LL gcd(LL a,LL b)
{
return b?gcd(b,a%b):a;
}
void read()
{
char c=getchar();
int f=0;
bool bo=false;
while (((c<'0')||(c>'9'))&&(c!='-'))
c=getchar();
if (c=='-')
f=1,c=getchar();
while ((c>='0')&&(c<='9'))
x=(x<<3)+(x<<1)+c-'0',c=getchar();
if (c=='.')
{
c=getchar();
loop :
switch (c)
{
case '(':
bo=true;
c=getchar();
goto loop;
default :
if ((c>='0')&&(c<='9'))
if (bo)
{
la=(la<<3)+(la<<1)+c-'0';
c=getchar();
(lb*=10)+=9;
goto loop;
}
else
{
if (c!='0')
{
for (;num;num--)
a*=10,b*=10;
a=(a<<3)+(a<<1)+c-'0',b*=10;
}
else
num++;
c=getchar();
goto loop;
}
}
}
LL g;
if (bo)
{
g=gcd(gcd(a,b),la);
a/=g;b/=g;la/=g;
g=gcd(la,lb);
la/=g;lb/=g;
(a*=lb)+=la;
b*=lb;
}
g=gcd(a,b);
a/=g;b/=g;
a+=b*x;
g=gcd(a,b);
a/=g;b/=g;
if (f)
printf("-");
if (b!=1)
printf("%lld/%lld",a,b);
else
printf("%lld",a);
return ;
}
int main()
{
read();
return 0;
}