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 with no 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
1
2
4
8
2
8

http://acm.hdu.edu.cn/showproblem.php?pid=1066

首先引用下leemars的报告:

这道题要求N!的最后一个非0数字是多少,如果用一般作法,先统计2和5的个数,然
后补乘2,得到的将是TLE。所以还需要再做简化:

为了把0去掉,我们把所有的因数2和5都提出来,放到最后再处理。N!中的N个相乘的
数可以分成两堆:奇数和偶数。偶数相乘可以写成(2^M)*(M!),M=N DIV 2。M!可以
递归处理,因此现在只需讨论奇数相乘。考虑1*3*5*7*9*11*13*15*17* ... *N(如果
N为偶数则是N-1),这里面是5的倍数的有5,15,25,35,... ,可以其中的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的结果是一个循环。
算出奇数的结果后,我们再回头看统计了多少个2和5需要乘入。把2和5配对完都是N
!后面的0,看剩下的2有几个。如果有剩下的2,考虑2^N的个位数又是2 4 8 6 2 4
8 6 ……每四项一个循环,找出这个个位数后,和前面的结果相乘,再取个位数就是
答案。由于我们完全把2和5的因素另外处理,所以在所有的乘法中,都只需要计算个位数乘法,并且只保留个位数的结果。

但让我很惊异的是:为什么我提交总是WA?后来我才知道,原因是这道题的N相当大
!达到了10^100!要用大数来处理!GPC四项编译开关全关的,自然查不出来!而且
上面这个算法换成大数后会很麻烦。还有什么别的好方法吗?

答案是有的。我们设F(N)表示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
= 6,4 / 2 = 2,6 / 2 = 8,8 / 2 = 4。比较特殊的就是2 / 2 = 12 / 2 = 6,
6 / 2 = 16 / 2 = 8。这样我们就可以得到如下式子:
代码:

table[N]
F(N) = ------------ (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个一循环,因此如果
有A个5,只需要除(A MOD 4)次2就可以了。A MOD 4只与A的最后两位数有关,很好求
算。剩下的5的倍数,由于5已经全部处理掉了,就变成[N/5]!。于是,我们可以得到
一个递归关系:
代码:

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

这样我们就得到了一个O(log5(N))的算法,整除5可以用高精度加法做,乘2再除10即
可。整个算法相当巧妙,写起来也比较轻松。

因为 2^N 是以4为循环节的

而且table[N]是以10为循环节的

所以从10开始

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

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

写出循环的末尾数字mod[20]={1,1,2,6,4,2,2,4,2,8,4,4,8,4,6,8,8,6,8,2}

整体思路解决了

然后就开始编程序喽!

#include<stdio.h>
#include<string.h>
int mod[]={,,,,,,,,,,,,,,,,,,,};
char n[];
int a[];
int main()
{
int i,c,t,len;
while(scanf("%s",n)!=EOF)
{
t=;
len=strlen(n);
for(i=;i<len;i++)
a[i]=n[len--i]-'';
while(len)
{
len-=!a[len-];
t=t*mod[a[]%*+a[]]%;
for(c=,i=len-;i>=;i--)
c=c*+a[i],a[i]=c/,c%=;
}
printf("%d\n",t);
}
return ;
}

Last non-zero Digit in N!的更多相关文章

  1. [LeetCode] Nth Digit 第N位

    Find the nth digit of the infinite integer sequence 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ... Note: n i ...

  2. [LeetCode] Number of Digit One 数字1的个数

    Given an integer n, count the total number of digit 1 appearing in all non-negative integers less th ...

  3. [Leetcode] Number of Digit Ones

    Given an integer n, count the total number of digit 1 appearing in all non-negative integers less th ...

  4. 【Codeforces715C&716E】Digit Tree 数学 + 点分治

    C. Digit Tree time limit per test:3 seconds memory limit per test:256 megabytes input:standard input ...

  5. kaggle实战记录 =>Digit Recognizer

    date:2016-09-13 今天开始注册了kaggle,从digit recognizer开始学习, 由于是第一个案例对于整个流程目前我还不够了解,首先了解大神是怎么运行怎么构思,然后模仿.这样的 ...

  6. [UCSD白板题] The Last Digit of a Large Fibonacci Number

    Problem Introduction The Fibonacci numbers are defined as follows: \(F_0=0\), \(F_1=1\),and \(F_i=F_ ...

  7. Last non-zero Digit in N!(阶乘最后非0位)

    Last non-zero Digit in N! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Jav ...

  8. POJ3187Backward Digit Sums[杨辉三角]

    Backward Digit Sums Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6350   Accepted: 36 ...

  9. Number of Digit One

    Given an integer n, count the total number of digit 1 appearing in all non-negative integers less th ...

  10. Java for LeetCode 233 Number of Digit One

    Given an integer n, count the total number of digit 1 appearing in all non-negative integers less th ...

随机推荐

  1. bzoj 3171 [Tjoi2013]循环格(MCMF)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3171 [题意] 给定一个方向矩阵,要求改变最少的格子,使得任意一个点都在一个环中. [ ...

  2. 二分+最短路 uvalive 3270 Simplified GSM Network(推荐)

    // 二分+最短路 uvalive 3270 Simplified GSM Network(推荐) // 题意:已知B(1≤B≤50)个信号站和C(1≤C≤50)座城市的坐标,坐标的绝对值不大于100 ...

  3. 解读MMS(Microsoft Media Server)协议

    下面是一次截取的MMS协议开始帧 部分(十六进制): 01000000cefa0bb0c00000004d4d5320 18000000000000000000000000000000 1600000 ...

  4. windwos iis 7.5 使用html 报405错误

    今天遇到了这个问题,网上搜一下基本上都是下面的答案: <form> 没有指定action的话就是文件自身了.  .html本身是不可执行的,如果要修改的话,在IIS中站点属性- 主目录 - ...

  5. gdb 技巧

    现实数组: 比如说要显示a[10]中全部的内容用 p a显示的是地址,用p *a显示的是第一个元素显示全部或某一个:p (int [10])*a或者p *a@10 如果你使用 p *a@3 或 p * ...

  6. 阿里云slb http https配置

  7. linux svn使用

    SVN是一种版本管理系统,前身是CVS,是开源软件的基石.即使在沟通充分的情况下,多人维护同一份源代码的一定也会出现混乱的情况,版本管理系统就是为了解决这些问题. SVN中的一些概念 : a. rep ...

  8. [置顶] 文件和目录(一)--unix环境高级编程

    普通文件和目录linux中最多的两类文件,linux中一共有七种类型的文件,如下: 1.普通文件 2.目录 3.字符特殊设备 4.块特殊设备 5.FIFO,又叫命名管道 6.Socket,即套接字 7 ...

  9. CLR探索应用程序域世界(上):Windbg SOS剖析揭示域世界

    在CLR的世界中,有一系列的令人Amazing的技术和架构.其中,CLR对应用程序在内存中内存分配,执行模型,程序之间的交互等一系列的技术,值得每一个致力于DotNet平台的技术人员深究. 编程人员在 ...

  10. word2007 每页显示表头

    word2007 每页显示表头 在Word 2007文档中,如果一张表格需要在多页中跨页显示,则设置标题行重复显示很有必要,因为这样会在每一页都明确显示表格中的每一列所代表的内容.在Word 2007 ...