UVA 202 有理数化为循环小数求循环节 UVA 11809 对数处理数据

来源:互联网 发布:mac 多屏幕切换快捷键 编辑:程序博客网 时间:2024/05/17 08:48

                  UVA 202  

                            题目的大致意思是给出有理数的分子和分母,要你找到化为循环小数后的循环节。

                            在此仅仅讨论有循环节非0的情况

                            给定分子a,分母b,假若没想到最多需要做除法的次数,可以用vector之类的玩意。

                            以下是我没有想到的地方:

                            原理:抽屉原理

                            a被b除,余数一共有b种可能(0 ~ b-1),当我在做第b+1次除法的时候,在这b+1个余数中一定会至少有重复的一对。

    我的做法是把每一次的商和余数作为一个结构体来储存,开了一个3010的数组,每一次计算后和之前数组里面的相比较

                            感觉用到抽屉原理很不错,以前没有这样想过。

                             自己的代码感觉仍然有些繁琐


                            

#include<iostream>#include<cstring>#include<algorithm>using namespace std;struct Node{int quotient, remain;bool friend operator==(const Node& a, const Node& b){return a.quotient == b.quotient&&a.remain == b.remain;}}ans[3010];int ans_length;int main(){ios_base::sync_with_stdio(false);int n, m, num, k; bool flag = false;Node test, *pn = nullptr;while (cin >> n >> m){num = n / m, k = n%m;if (k == 0)flag = true;else{while (k != 0){k *= 10, test.quotient = k / m, test.remain = k%m, k %= m;pn = find(ans, ans + ans_length, test);if (ans + ans_length != pn)break;elseans[ans_length++] = test;}}cout << n << '/' << m << " = " << num << ".";if (k == 0){for (int i = 0; i < ans_length - 1; ++i)cout << ans[i].quotient;if (!flag)cout << test.quotient;cout<< "(0)\n   1 = number of digits in repeating cycle\n";}else{if (ans_length>50){for (int i = 0; ans + i != pn; ++i)cout << ans[i].quotient;cout << "(";for (Node* pi = pn; pi-ans<50; ++pi)cout << pi->quotient;cout << "...)\n   " << ans + ans_length - pn << " = number of digits in repeating cycle\n";}else{for (int i = 0; ans + i != pn; ++i)cout << ans[i].quotient;cout << "(";for (Node* pi = pn; pi != ans + ans_length; ++pi)cout << pi->quotient;cout << ")\n   " << ans + ans_length - pn << " = number of digits in repeating cycle\n";}}cout << endl;ans_length = 0; flag = false;}return 0;}



               UVA 11809    

考虑到数据的范围,A∈(0,10),M∈(0,10),E ∈[1,30],数据量并不是很大,很自然的考虑打表,然后在表中查询,关键是怎么生成表的问题。

0.1111111(M+1个)* 2^(2^E-1)  =   A*10^B

 这个公式是我最开始想到的打表的依据,可是后来发现E最大可以到30,double是存不下的。

以下是我没有想到的地方

  两边可以取对数,因为在计算左边的时候,M和E是我们穷举的,因此左边的值是已知的,不妨另左边的值为k

lgk = lg A + B 

变成这样的式子,只需要通过强制转换提取整数部分算出B,然后相减提取小数部分就算出A 了

以下是代码

#include<cstdio>#include<cmath>#include<cstring>using namespace std;const double lg2 = log10(2), accuracy = 1e-5;double mantissa[10][31];long long num[10][31];char con[100];int main(){double a, b, c;long long d;for (int i = 0; i < 10;++i)for (int j = 1; j <= 30; ++j){a = log10(1 - pow(0.5, i + 1)), b = lg2*((1 << j) - 1), c = a + b;num[i][j] = (long long)c, mantissa[i][j] = pow(10, c - num[i][j]);}while (scanf("%s", con)){if (strlen(con) == 3)break;con[17] = ' ';sscanf(con, "%lf%lld", &a, &d);for (int i = 0; i < 10; ++i)for (int j = 1; j <= 30; ++j)if (num[i][j] == d && ((fabs(a - mantissa[i][j]) < accuracy) || (fabs(a / 10 - mantissa[i][j]) < accuracy)))printf("%d %d\n", i, j), j = 31, i = 10;}return 0;}

0 0
原创粉丝点击