题目描述
写一个程序,输入一个形如 DN 的分数,输出它的小数形式。如果小数有循环节的话,把循环节放在一对圆括号中。
例如,13=0.33333333…31=0.33333333… 写成 0.(3)0.(3),41333=0.123123123…33341=0.123123123… 写成 0.(123)0.(123),整数 x 写成 x.0。
输入格式
输入包含两个整数 N 和 D(1≤N,D≤105)。
输出格式
输出按照上面规则计算出的小数表达式。如果结果长度大于 7676,每行输出 7676 个字符。
输入输出样例
输入 #1复制
45 56
输出 #1复制
0.803(571428)
说明/提示
翻译来自NOCOW
USACO 2.4
code
#include<iostream>
#include<fstream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
int n,d,k,w,sum,len;
//w用来记录循环节开始(左括号)的位置,sum为输出使用的计数器
string ans;
//答案
int pd[100005];
//pd数组用来记录每个余数出现的位置,判断余数是否重复,便于记录循环节开始(左括号)的位置。根据题目1<=N,D<=100000可得知余数最终不会超过99999
int main()
{
scanf("%d%d",&n,&d);
k=n/d,w=-1;
do
{
ans=char(k%10+'0')+ans;
//这种方法要把拆分出来的整数放到前面去,不然会反过来,因为它先拆分个位,再拆分十位,直接加会使个位在前,直接加会使十位在后,
k/=10;
}while(k>0);
//拆分结果的整数部分进ans。由于0也算是整数部分,所以无论如何也要拆分一次,用do{}while(),不然用for() 整数部分为0时就不会拆进去,因为k=0了
ans+='.';
//鉴于结果无论如何至少有一位小数,加个小数点
n=n%d;
//被除数取余,开始模拟小数部分的除法运算
do
{
if(pd[n]!=0)
{
w=pd[n];
break;
}
//如果余数有重复,说明这是一个循环小数,上一个n出现的位置便是循环节开始(左括号)的位置
else pd[n]=ans.size();
//否则就记下这个余数变为被除数后对应的商出现的位置,以便未来判断和记录
n*=10;
//n变成被除数,末尾加0(N,D一定是正整数,不存在小数可加在末尾)
k=n/d;
ans+=char(k+'0');
n=n%d;
//模拟除法
}while(n!=0);
//由于结果如果是正整数的话,末尾也得加0,用do()while{}
if(w!=-1) ans+=')';
//如果结果是一个循环小数,在末尾加个右括号,便于输出
len=ans.size();
for(int i=0;i<len;i++)
{
if(i==w)
{
putchar('(');
i--;
w=-1;
}
else putchar(ans[i]);
sum++;
if(sum%76==0)
putchar('\n');
}
return 0;
}