社会我赞哥
说在前面
今天,也就是公元2019年4月26日,下午五点一刻左右,多才多艺的yuzan1830请求本蒟蒻帮他把一个小数转化成分数,类似于下面这样:
1.2
3
˙
4
˙
=
611
495
1.2\dot 3\dot 4=\frac{611}{495}
1.23˙4˙=495611
yuzan1830事先准备好了Dev-C++,准备让本蒟蒻在教室的一体机上大显身手献丑,故事就这样开始了……
接受挑战
首先要对输入和输出予以限制:若输入的小数有循环节,将循环节用一对小括号括起来;输出的分数必须是最简分数,分母为 1 1 1时仍要输出分母,分数值大于 1 1 1时输出假分数。
样例输入
1.2(34)
样例输出
611/495
本蒟蒻在数竞大佬面前瑟瑟发抖。
本人的思路:
首先将给定的数分成两部分:有限的部分
A
A
A和循环的部分
B
B
B。
1.2
3
˙
4
˙
=
1.2
+
0.0
3
˙
4
˙
1.2\dot 3\dot 4=1.2+0.0\dot 3\dot 4
1.23˙4˙=1.2+0.03˙4˙
为了方便,计算过程中所有的数据都用分数,即用分子和分母进行运算。
A
A
A可以很简单地边读入边处理。
1.2
=
12
10
1.2=\frac{12}{10}
1.2=1012
关键在于如何把
B
B
B转化成分数。下面是过程。
PS:yuzan1830直言这是小学奥数内容。
B
=
0.0
3
˙
4
˙
100
B
=
3.4
3
˙
4
˙
99
B
=
3.4
B
=
3.4
99
=
34
990
\begin{aligned} B&=0.0\dot 3\dot 4\\ 100B&=3.4\dot 3\dot 4\\ 99B&=3.4\\ B&=\frac{3.4}{99}=\frac{34}{990} \end{aligned}
B100B99BB=0.03˙4˙=3.43˙4˙=3.4=993.4=99034
一般地,记第一个循环节及其之前的小数部分为
C
C
C,循环节长度为
k
k
k,
b
a
s
e
=
1
0
k
base=10^k
base=10k,则
B
=
C
⋅
b
a
s
e
b
a
s
e
−
1
B=\frac{C\cdot base}{base-1}
B=base−1C⋅base
然后本蒟蒻就开始在触摸屏上写了,依旧瑟瑟发抖。
事后凭印象写出的代码如下(后来的事实证明,这个代码漏洞百出):
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
struct fract{
int n,d;
fract(int n=0,int d=1):n(n),d(d){};
};
int main(){
char s[1000];
while(scanf("%s",s+1)==1){
int len=strlen(s+1),i;
fract A,C;bool f=0;
for(i=1;i<=len;i++){
if(s[i]=='(')break;
if(s[i]=='.'){f=1;continue;}
A.n=A.n*10+s[i]-'0';
if(f)A.d*=10,C.d*=10;
}
int base=1,ans_n,ans_d;
for(i++;i<len;i++){
C.n=C.n*10+s[i]-'0',C.d*=10;
base*=10;
}
if(base==1)ans_n=A.n,ans_d=A.d;
else ans_n=A.n*C.d*(base-1)+A.d*C.n*base,ans_d=A.d*C.d*(base-1);
int gcd=__gcd(ans_n,ans_d);
cout<<ans_n/gcd<<'/'<<ans_d/gcd<<endl;
}
return 0;
}
对于数据
1.2
,
1.2
3
˙
4
˙
1.2,1.2\dot 3\dot 4
1.2,1.23˙4˙和
0.
3
˙
0.\dot 3
0.3˙,代码得出了正确的结果,但是
1.
2
˙
8571
4
˙
1.\dot 28571\dot4
1.2˙85714˙得出的答案分母是负数。
显然溢出了。int
全改成long long
就好了,毕竟运算过程中没有进行约分。(main
函数当然还是要返回int
)
说在后面
之所以用结构体fract
,其实是想重载运算符,直接对分数
A
,
B
,
C
A,B,C
A,B,C进行运算(曾经在某道数学期望题中写过),但是好像当场写崩。于是直接拿分子分母来算。
事后重载运算符写出的代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
struct fract{
LL n,d;
fract(LL n=0,LL d=1):n(n),d(d){};
fract operator+(fract b){
LL nn=n*b.d+b.n*d,nd=d*b.d,gcd=__gcd(nn,nd);
return fract(nn/gcd,nd/gcd);
}
fract operator*(LL b){
LL nn=n*b,nd=d,gcd=__gcd(nn,nd);
return fract(nn/gcd,nd/gcd);
}
fract operator/(LL b){
LL nn=n,nd=d*b,gcd=__gcd(nn,nd);
return fract(nn/gcd,nd/gcd);
}
friend void write(fract x){
printf("%lld/%lld\n",x.n,x.d);
}
};
char s[1000];
int main(){
while(scanf("%s",s+1)==1){
int len=strlen(s+1),i;
fract A,C,D(1,1),ans;bool f=0;
for(i=1;i<=len;i++){
if(s[i]=='(')break;
if(s[i]=='.'){f=1;continue;}
if(f)D=D/10,A=A+D*(s[i]-'0');
else A=A*10+(s[i]-'0');
}
LL base=1;
for(i++;i<len;i++){
D=D/10,base*=10;
C=C+D*(s[i]-'0');
}
if(base==1)ans=A;
else ans=A+C*base/(base-1);
write(ans);
}
return 0;
}
另外,yuzan1830十分善良地没有出特别刁钻的数据,导致本蒟蒻在大佬面前没有丢失颜面。
最后感谢yuzan1830 浪费充实了我近一个小时的时间。