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

  

如题:

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张图片

    把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 
#include 
#include 
#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<

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

                                                                                Over~


你可能感兴趣的:(AC,Dreamer,数论)