https://vjudge.csgrandeur.cn/problem/POJ-1930
邁克在最後一刻拼命地趕着完成他的論文。在接下來的3天裏,他需要將所有的研究筆記整理成較爲連貫的形式。
不幸的是,他注意到他在計算方面非常粗心。每當他需要進行算術運算時,他只是將其輸入計算器,並將他認爲相關的答案寫下來。
每當顯示一個循環小數時,邁克只是簡單地記錄下前幾位數字,然後加上“...”。例如,他可能會寫下“0.3333...”而不是“1/3”。
不幸的是,他的結果需要精確的分數!他沒有時間重新計算每個計算,所以他需要你寫一個程序(而且要快!)來自動推斷原始分數。
爲了使這個過程可行,他假設原始分數總是產生給定數字序列的最簡分數;他所說的最簡是指分母最小的分數。
此外,他假設他沒有忽略寫下重要的數字;即使這個循環部分的小數展開全是零,也沒有遺漏記錄。
輸入
有幾個測試用例。對於每個測試用例,輸入的一行是形如“0.dddd...”的字符串,其中dddd是由1到9個數字組成的,不能全爲零。
最後一個用例後面跟着一行包含0的輸入。
輸出
對於每個用例,輸出原始分數。
0.2...
0.20...
0.474612399...
0
2/9
1/5
1186531/2500000
0.308048647...
154024322/499999995
0.012345679...
1/81
0.1428571...
0.14285714...
0.142857142...
1/7
解答
循環數的規律
0.233233 這種循環就是 233/999 分母9的出現個數是循環節的長度
0.666233233233 這種循環就是 666233-666 / 999000 也就是整個數減去非循環節 然後除以999000
分母9的出現個數是循環節的長度 分母0出現的次數是非循環節的長度
但是題目 並不保證0.666233是以哪個循環節進行循環,所以要逐個嘗試循環節,然後得到最簡,也就是分母最小的分數。
#include <iostream>
#include <string>
#include <limits>
#include <math.h>
#include <cmath>
#include <stdlib.h>
using namespace std;
typedef unsigned long long ULL;
string str;
ULL nine(int len) {
return pow(10, len )-1;
}
ULL gcd(ULL a, ULL b)
{
return b ? gcd(b, a % b) : a;
}
void solve(string digit) {
ULL len = digit.size();
ULL mindown = numeric_limits<ULL>::max();
ULL minup = 0;
//得到整個數據
ULL a = atoi(digit.c_str());
for (int i = 1; i <= len; i++) {
//逐個嘗試 循環節
ULL b = atoi(digit.substr(0, len - i).c_str());
//添加九位
ULL down = nine(i);
//添加零位
down *= pow(10, len - i);
//計算aa/a + bb/b
ULL up = a-b;
//通分分子分母
ULL d = gcd(up, down);
up = up / d; down = down / d;
if (mindown > down) {
mindown = down;
minup = up;
}
}
cout << minup << "/" << mindown << endl;
return;
}
int main()
{
#if 0
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
while (cin >> str) {
if (str == "0") break;
int len = str.length() - 5;
string digit = str.substr(2, len);
ULL n = atoi(digit.c_str());
if (n == 0) {
cout << "0/1" << endl;
continue;
}
solve(digit);
}
#if 0
fclose(stdin);
fclose(stdout);
system("out.txt");
#endif
}