UVa202 循环小数

题目

题目

输入多组数据,每组输入整数a和b,(0<=a<=3000, 1<=b<=3000),输出a/b的循环小数表示以及循环字节长度。

样例输入

76 25
5 43
1 397

样例输出

76/25 = 3.04(0)
   1 = number of digits in repeating cycle
(空行)
5/43 = 0.(116279069767441860465)
   21 = number of digits in repeating cycle
(空行)
1/397 = 0.(00251889168765743073047858942065491183879093198992...)
   99 = number of digits in repeating cycle

思路

非常惭愧,我想了很多天才想明白这个题怎么做。

列竖式是怎么计算小数的

在计算两数相除的时候,幼儿园老师教我们应该列竖式计算。其实追究其本质,我们是怎样计算一个小数的?

5/7为例:

  1. 计算5/7,结果是当前位的数值(这是第一次计算,所以这里说的当前位其实是整数部分,后面就不是了)
  2. 计算5%7,得出余数m(此时m=5)
  3. a=m*10,即计算507,重复上面的两步
  4. 如此下去,就能通过第一步一直得到小数各位

这里有几个细节:

  1. 为啥第三步要算m*10呢?其实这就相当于列竖式的时候,得出来余数以后,添个0,继续往后算,比如下面这个图片,加上这个红色的0就相当于m*10的功能

  1. 第一次计算的时候a/b得出的是整数部分数值,但是后面的话是十分位、百分位、千分位等等,肯定是只有一位数字的。这是因为,我们以前经常会遇到遍历整数各个位置,常用的方法是用a%10来取一个数字的个位,其实,第三步就是这种计算的逆运算,运算结果应当也是只有一个位的数字才对。

本题的大致思路

其实,如果我们要是在上面的方法中,计算余数的时候,如果计算出的余数前面出现过,我们就不需要再算了,因为重复出现同一个余数,后面算的数字都一样,试一试就明白了。

也就是说,循环节是两次余数相等的位置中间的数字才对。

一个想法就是,用数组当表,下标代表余数,存储第一次算出这个余数的位置。

第二个问题就是,余数的取值范围肯定是0到b,能取到0,不能取到b,大于等于b是不可能的,这是余数的性质。
进一步的推广一下,循环节的长度不可能超过b。

实现

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            shit(scanner.nextInt(), scanner.nextInt());
        }
    }

    public static void shit(int a, int b) {
        int[] arr = new int[3005]; //余数表
        int[] fuck = new int[3005];//小数各位数字

        System.out.printf("%d/%d = ", a, b);

        int y = a / b;

        for (int i = 1; i <= b; i++) {
            a = (a % b) * 10;

            int r = a % b;
            int x = a / b;

            fuck[i] = x;

            if (arr[r] == 0 || (arr[r] != 0 && fuck[arr[r]] != fuck[i])) {
                arr[r] = i;
            } else {
                int t = i - arr[r];
                System.out.printf("%d.", y);
                for (int j = 1; j < arr[r]; j++)
                    System.out.printf("%d", fuck[j]);
                System.out.printf("(");
                for (int j = arr[r]; j < Math.min(i, arr[r] + 50); j++) {
                    System.out.printf("%d", fuck[j]);
                }
                if (t > 50) System.out.print("...");
                System.out.printf(")\n");
                System.out.printf("   %d = number of digits in repeating cycle\n\n", t);
                break;
            }
        }
    }
}
上一篇
下一篇