小數化分數 模擬題
小數化分數
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; }