好怀念的题,刚刚进来ACM时老师讲过,不过后来也没有去做,现在又遇上了。
题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=138
题目描述:输入整数a和b,输出a/b的循环小数表示以及循环节长度。如a=5,v=43,小数表示为0.(116279069767441860465),循环节长度为21
思路:
(1)模拟前300次运算,将小数每一个部分存储到一个int数组里,再用string流转化为字符串
【注意,不能直接long double a,b,然后a/b,这样的结果是不准确的,计算机由于使用二进制运算,浮点数计算会有误差,对于这道题来说一点误差就意味着错误。】
image.png
(2)找循环节。方法是,先从小数点后第一位开始,由两个开始往后面找字符串(循环节为1的会单独拿出来处理),比如说116279069767441860465,先找到11,然后将他变为两倍(1111),然后在那个500位的小数里面找有无出现这个字符串,然后看紧跟着11的两位(这里是62)是否相等,如果是则找到了循环节。
代码如下:
#include<iostream>
#include<sstream>
#include<string>
#include <iomanip>
using namespace std;
int main(void)
{
int i,j;
int a,b;
int magnification=10;
int num[300];
int flag=0;
string decimal;
string child_decimal;
stringstream ss;
string::size_type idx;
cin >> a >> b;
cout << a / b <<'.';
if (a / b > 0) a = a - (a / b)*b;
for (i = 1; i <= 300; i++)
{
if ((a* magnification) / b == 0)
{
a = a * 10;
num[i] = 0;
ss << num[i];
}
else
{
num[i] = (a* magnification) / b;
ss << num[i];
a = a* magnification - ((a*magnification)/b)*b;
}
}
ss >> decimal;
for(i=0;;i++)
{
for (j = 2; j <= 110; j++)
{
child_decimal = decimal.substr(i, j);
child_decimal += child_decimal;
idx = decimal.find(child_decimal);//在a中查找b.
if (idx != string::npos&&decimal.substr(i, j)== decimal.substr(i+j, j))
{
cout << decimal.substr(0, i);
if (child_decimal.substr(0, child_decimal.length() / 4) + child_decimal.substr(0, child_decimal.length() / 4) == child_decimal.substr(0, child_decimal.length() / 2))
{
cout << '(' << child_decimal.substr(0, child_decimal.length() / 4) << ')' << endl;
cout << child_decimal.length() / 4 << "=循环节长度" << endl;
}
else
{
cout << '(' << child_decimal.substr(0, child_decimal.length() / 2) << ')' << endl;
cout << child_decimal.length() / 2 << "=循环节长度" << endl;
}
flag = 1;
break;
}
}
if (flag == 1) break;
}
}
原题给出的例子都能测试通过。
运行截图:
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
但似乎运行效率不高,如果真的提交,那么有可能会超时。
而且会溢出。