zoukankan      html  css  js  c++  java
  • 1066N !最右边非零数

    http://hi.baidu.com/nicker2010/item/4fa83c4c5050b3e5a4c066ec

    另一个

    Last non-zero Digit in N!

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 5695    Accepted Submission(s): 1416

    Problem Description

    The expression N!, read as "N factorial," denotes the product of the first N positive integers, where N is nonnegative. So, for example, 
    N N! 
    0 1 
    1 1 
    2 2 
    3 6 
    4 24 
    5 120 
    10 3628800 

    For this problem, you are to write a program that can compute the last non-zero digit of the factorial for N. For example, if your program is asked to compute the last nonzero digit of 5!, your program should produce "2" because 5! = 120, and 2 is the last nonzero digit of 120. 

    Input

    Input to the program is a series of nonnegative integers, each on its own line withno other letters, digits or spaces. For each integer N, you should read the value and compute the last nonzero digit of N!.

    Output

    For each integer input, the program should print exactly one line of output containing the single last non-zero digit of N!.

    Sample Input

    1 2 26 125 3125 9999

    Sample Output

    124828

    Source

    South Central USA 1997 

    这道题请求N!的最后一个非0数字是几许,若是用一般作法,先统计25的个数,然
    后补乘2,获得的将是TLE。所以还须要再做简化:
    为了把0去掉,我们把所有的因数25都提出来,放到最后再处理惩罚。N!中的N个相乘的
    数可以分成两堆:奇数和偶数。偶数相乘可以写成(2^M*M!),M=N DIV 2M!可以
    递归处理惩罚,是以如今只需评论辩论奇数相乘。推敲1*3*5*7*9*11*13*15*17* ... *N(若是
    N为偶数则是N-1),这里面是5的倍数的有5152535... ,可以此中的5提出来
    ,变成(5^P*1*3*5*7*9* ... ),后面括号中共P项,P=N DIV 5+1) DIV 2,而后
    面的括号又可以持续提5出来,递归处理惩罚。如今剩下的数是1 * 3 * 7 * 9 * 11 * 13
    * 17 * 19 * ... 。这些数我们只须要他们的个位数,因为(1 * 3 * 9 * 11 * 13
    * ... ) MOD 10 = 1 * 3 * 7 * 9 * 1 * 3 * ... ) MOD 10。我们列出余数表,
    1 3 1 9 9 7 9 1 1 3 1 9 9 7 9 ……。我们发明每八项MOD 10的成果是一个轮回。
    算出奇数的成果后,我们再回头看统计了几许个25须要乘入。把25配对完都是N
    !后面的0,看剩下的2有几个。若是有剩下的2,推敲2^N的个位数又是2 4 8 6 2 4
    8 6 ……每四项一个轮回,找出这个个位数后,和前面的成果相乘,再取个位数就是
    答案。因为我们完全把25的身分别的处理惩罚,所以在所有的乘法中,都只须要策画个位数乘法,并且只保存个位数的成果。

    但让我很惊奇的是:为什么我提交老是WA?后来我才知道,原因是这道题的N相当大
    !达到了10^100!要用大数来处理惩罚!GPC四项编译开关全关的,天然查不出来!并且
    上方这个算法换成大数后会很麻烦。还有什么此外好办法吗?
    答案是有的。我们设FN)默示N!的尾数。
    先推敲简单的。推敲某一个N!N < 10),我们先将所有5的倍数提出来,用1庖代本来
    5的倍数的地位。因为5的倍数全被提走了,所以如许就不会呈现尾数0了。我们先把
    0..9的阶乘的尾数列出来(重视,5的倍数的地位上是1),可以获得table[0..9] =
    1, 1, 2, 6, 4, 4, 4, 8, 4, 6)。对于N < 5,直接输出table[N]即可;对于N >
    = 5,因为提出了一个5,是以须要一个2与之配成10,即将尾数除以2。重视到除了0
    !1!,阶乘的最后一个非零数字必为偶数,所以有一个很特此外除律例律:2 / 2
    = 64 / 2 = 26 / 2 = 88 / 2 =4。斗劲特别的就是2 / 2 = 12 / 2 = 6
    6 / 2 = 16 / 2 = 8。如许我们就可以获得如下式子:
    代码:
                   table[N]
    FN) = ------------ 0 <= N < 10
                   2^[N/5]
    再推敲错杂的。推敲某一个N!N >= 10),我们先将所有5的倍数提出来,用1庖代原
    5的倍数的地位。因为5的倍数全被提走了,所以如许就不会呈现尾数0了。我们观
    察一下剩下的数的乘积的尾数,经由过程table表,我们发明这10个数的乘积的尾数是6
    6 * 6的尾数还是6,是以我们将剩下的数每10个分成一组,则剩下的数的乘积的尾数
    只与最后一组的景象有关,即与N的最后一位数字有关。因为我们把5的倍数提出来了
    N!中一次可以提出[N/5]5的倍数,有几许个5,就须要有几许个2与之配成10,所
    以有几许个5,最后就要除以几许个2。重视到除2的成果变更是4个一轮回,是以若是
    A5,只须要除(A MOD 4)次2就可以了。A MOD 4只与A的最后两位数有关,很好求
    算。剩下的5的倍数,因为5已经全部处理惩罚掉了,就变成[N/5]!。于是,我们可以获得
    一个递归关系:
    代码:
                   F[N/5]) * table[N的尾数] * 6
    FN) = ----------------------------------- N > 10
                   2^[N/5] MOD 4
    如许我们就获得了一个Olog5N))的算法,整除5可以用高精度加法做,乘2再除10
    可。全部算法相当奇妙,写起来也斗劲轻松。

    因为 2^N 是以4为轮回节的

    并且table[N]是以10为轮回节的

    所以从10开端

                   F[N/5]) * table[N的尾数] * 6
    FN) = ----------------------------------- N > 10
                   2^[N/5] MOD 4

    右边的式子除了F[n/5]外 是以20为轮回节的

    写出轮回的末尾数字mod[20]={11264224284484688682}

    整体思路解决了

    #include<stdio.h>

    #include<string.h>

    #define N 1000

    int b[20]={1,1,2,6,4,2,2,4,2,8,4,4,8,4,6,8,8,6,8,2};

    int main()

    {

        int len,ans,c,i,a[N];

        char s[N];

        while(scanf("%s",s)!=EOF)

        {

            len=strlen(s);

            for(i=0;s[i]!='';i++)

              a[i]=s[len-i-1]-'0';

          ans=1;

          while(len)

          {

              ans=ans*b[a[1]%2*10+a[0]]%10;//取后两位20的循环

              for(c=0,i=len-1;i>=0;i--)//除于5

              {

                  c=c*10+a[i];

                  a[i]=c/5;

                  c=c%5;

              }

              len-=!a[len-1];//将0去掉

          }

          printf("%d ",ans);

        }

        return 0;

    }


  • 相关阅读:
    Cxx11 stdchrono库详解
    Oracle中文乱码
    Javascript 编程小技巧总结(部分内容借鉴他人)
    从文档流角度理解浏览器页面渲染引擎对元素定位的解析
    JS重点特性——闭包详解
    用一段JS代码来比较各浏览器的极限内存与运算速度
    前端开发人员需知——浏览器详解
    Js变量定义——fn里 var与不var的区别
    Js文字特效—文字段逐个变色循环
    html5 canvas画图之图形随拖动而复制(有操作指示)
  • 原文地址:https://www.cnblogs.com/thefirstfeeling/p/4410817.html
Copyright © 2011-2022 走看看