欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

最长的循环节 之 有趣的无限循环小数

程序员文章站 2024-03-19 18:56:52
...

  最长的循环节 之 有趣的无限循环小数

如题:

1035 最长的循环节 最长的循环节 之 有趣的无限循环小数

基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题

正整数k的倒数1/k,写为10进制的小数如果为无限循环小数,则存在一个循环节,求<=n的数中,倒数循环节长度最长的那个数,假如存在多个最优的答案,输出所有答案中最大的那个数。

1/6= 0.1(6) 循环节长度为1
1/7= 0.(142857) 循环节长度为6
1/9= 0.(1)  循环节长度为1
Input
输入n(10 <= n <= 1000)
Output
输出<=n的数中倒数循环节长度最长的那个数
Input示例
10
Output示例
7

题目分析

    题目要求就是求<=n( n∈[10,1000] )的数中倒数循环节长度最长的那个数。

这就意味着我们要求出所有数的倒数的循环节长度(打表),然后逐一比较得出最长的那个数。

怎样打表?那我们就要参考康明昌老师一篇paper所给出的定理来分析一下。

首先看分母为7的循环小数表示式
                             最长的循环节 之 有趣的无限循环小数

    把1/7的循环节142 857轮换排列:如果从2出发,得285 714,这是2/7的循环节;如果从4出发,得428 571,这是3/7的循环节。以此类推。


不知大家是否已经发现规律:(可以多举几组例子,这里我就只拿7举例了哈)

    1.对于无限循环的小数,循环节长度只与分母有关?且长度小于分母?

    2.对于同分母真分数的循环小数来说,循环节里出现的数字都是一样的,只是有不同的排列组合?


要得证 我们首先得来看一个定理:为同余符号)

    定理1: 如果 1 ≤ b < a,  a 沒有2或5的質因數, 並且 a 與 b 互質, 

那麼 b/a 的循環節位數恰好等於e: min{ e ∈ N : 10^e ≡ 1 (mod a) }。


证明规律1

    由上面给出的定理可知,对于分数b/a,循环节位数 e = min{ e ∈ N : 10^e ≡ 1 (mod a) }.

即循环节长度e只由分母a决定;

    又由费马小定理可知,对质数p(除了2、5。10是它们的倍数)有10^(p-1) mod p=1。

显然循环节长度最大为 p-1. 循环节长度e必然小于分母p

证明规律2

    因为: 1/7 = 0.142 857……    

    由定理1得: 10*(1/7)= 1.428 571……

    因此: 3/7 = [10/7] = 0.428 571……

    同理,考虑 [30/7] = 2/7,[20/7] = 6/7,[60/7] =4/7,[40/7] = 5/7,[50/7] = 1/7。得证!


3.另外我们要思考的是为什么定理中指出没有 2或5?

    因为1/2=0.5、1/5=0.2,这些有限小数对循环节长度是不影响的。

    举个例子:73/35 = 73/(5*7) = (2*73)/(10*7) = (1/10)·(146/7) = (1/10)·{20 + (6/7)}

因此, 对于分数73/35,其的循环节与 6/7 的循环节是一样的,都是 867142 ……    是不是很神奇


代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#define INF 0x3f3f3f3f
#define NMAX 1001
using namespace std;
int n, res[NMAX];
void init(){                  //打表  定理:min{e|10^e ≡ 1(mod n),e∈N+}
    memset(res, -1, sizeof(res));
    res[1]=0;
    for (int i = 2; i < NMAX; ++i) {    //分母	只有分母影响循环节
        int t = i;
        while (t%5==0)                  //约去因子2和5	为有限小数
            t/=5;
        while (t%2==0)
            t/=2;
        if (res[t] != -1) {   //已算过
            res[i] = res[t];
            continue;
        }
        //未算过 即质数	
        //其实本质只需要计算所有分母为质数的循环节 质数的倍数的数(分母)的循环节位数===这个质数(分母)的循环节位数
        int x = 10;
        for (int j = 1; j <= i; ++j) {  //循环节位数 必小于分母
            x %= i;           //同定理 无影响(同余定理)
            if (x==1){
                res[i] = j;
                break;
            }
            x*=10;
        }
    }
}
int main(){
    init();
    while (cin>>n){
        int ans = 7;    //n>=10
        for (int i = 11; i <= n; ++i) {
            if (res[ans] <= res[i]) {
                ans = i;     //取max
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

    有趣的小数我们就先讨论到这,更多关于循环节的定理知识大家可以去看循环节_*。里面有相关定理证明以及更深入的探讨。

                                                                                Over~