HDU-1066 Last non-zero Digit in N!

Last non-zero Digit in N!

Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/32768 K (Java/Others)

Problem Description

The expression N ! N! N!, read as “N factorial,” denotes the product of the first N N N positive integers, where N N N is nonnegative. So, for example,

N N N N ! N! N!
0 0 0 1 1 1
1 1 1 1 1 1
2 2 2 2 2 2
3 3 3 6 6 6
4 4 4 24 24 24
5 5 5 120 120 120
10 10 10 3628800 3628800 3628800

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

Output

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

Sample Input

1 
2 
26 
125 
3125 
9999

Sample Output

1
2
4
8
2
8

Reference Code

#include <cstdio>
#include <cstring>
const int MAXN = 1e3 + 10;
int lst[] = {1, 1, 2, 6, 4, 2, 2, 4, 2, 8};
int lst1[] = {3, 3, 0, 3, 1, 1, 1, 2, 1, 3};
int lst2[] = {2, 4, 8, 6};
int num[MAXN], len;
char str[MAXN];
int solve(){
    if (len == 1) return lst[num[0]];
    int tail = num[0], c = 0;
    for (int i = len - 1; i >= 0; i--){
        c = c * 10 + num[i];
        num[i] = c / 5;
        c %= 5;
    }
    while (!num[len-1]) len--;
    int k = (num[1] * 10 + num[0]) & 3;
    return lst2[(lst1[tail] - k + 4) & 3] * solve() % 10;
}
int main(){
    while (~scanf("%s",str)){
        len = strlen(str);
        for (int i = 0; i < len; i++)
            num[i] = str[len - i - 1] - '0';
        printf("%d\n",solve());
    }
}

Tips

g ( n ) g(n) g(n) n n n最后一个不是 0 0 0的数字,易证,如果 g ( a ) , g ( b ) ≠ 5 g(a),g(b)\ne5 g(a),g(b)̸=5,有 g ( a b ) = g ( g ( a ) g ( b ) ) g(ab)=g\left(g(a)g(b)\right) g(ab)=g(g(a)g(b))
因此,我们可以把 n ! n! n!分解为 (*) n ! = l × ∏ i = 1 k 5 i × 2 k = l × k ! × 1 0 k n!=l\times\prod_{i=1}^{k}5i\times2^k=l\times k!\times10^k\tag{*} n!=l×i=1k5i×2k=l×k!×10k(*)其中 k = ⌊ n 5 ⌋ k=\lfloor\frac{n}{5}\rfloor k=5n,然后利用 g ( n ! ) = g ( g ( l ) g ( k ! ) ) g(n!)=g\left(g(l)g(k!)\right) g(n!)=g(g(l)g(k!))递归地求解本题。

下面,我们分两步求解 g ( l ) g(l) g(l)

首先,将 ( ∗ ) (*) ()式两边同除 ∏ i = 1 k 5 i × 2 k \prod_{i=1}^{k}5i\times2^k i=1k5i×2k,我们得出 l = 1 2 k ( ∏ i = 0 ⌊ n 10 ⌋ − 1 ∏ 1 ⩽ j ⩽ 9 , j ≠ 5 ( 10 i + j ) ⋅ ∏ 1 ⩽ i ⩽ m , i ≠ 5 ( 10 ⌊ n 10 ⌋ + i ) ) = h 2 k l=\frac{1}{2^k}\left(\prod_{i=0}^{\lfloor\frac{n}{10}\rfloor-1}\prod_{1\leqslant j\leqslant 9,j\ne5}(10i+j)\cdot\prod_{1\leqslant i\leqslant m,i\ne5}\left(10\lfloor\frac{n}{10}\rfloor+i\right)\right)=\frac{h}{2^k} l=2k1i=010n11j9,j̸=5(10i+j)1im,i̸=5(1010n+i)=2kh

其中 m = n  mod  10 m=n\text{ mod }10 m=n mod 10

我们先求解 g ( h ) g(h) g(h)

不难发现,若有 5 ∤ t i , ∀ 1 ⩽ i ⩽ s 5\nmid t_i,\forall 1\leqslant i \leqslant s 5ti,1is,则 g ( ∏ i = 1 s t i ) = g ( ∏ i = 1 s ( t i  mod  10 ) ) g\left(\prod_{i=1}^{s}t_i\right)=g\left(\prod_{i=1}^{s}(t_i\text{ mod }10)\right) g(i=1sti)=g(i=1s(ti mod 10))

因此, g ( ∏ i = 0 ⌊ n 10 ⌋ − 1 ∏ 1 ⩽ j ⩽ 9 , j ≠ 5 ( 10 i + j ) ) = g ( ( ∏ 1 ⩽ j ⩽ 9 , j ≠ 5 j ) ⌊ n 10 ⌋ ) = 6 g\left(\prod_{i=0}^{\lfloor\frac{n}{10}\rfloor-1}\prod_{1\leqslant j\leqslant 9,j\ne5}(10i+j)\right)=g\left(\left(\prod_{1\leqslant j\leqslant 9,j\ne5}j\right)^{\lfloor\frac{n}{10}\rfloor}\right)=6 gi=010n11j9,j̸=5(10i+j)=g1j9,j̸=5j10n=6 g ( ∏ 1 ⩽ i ⩽ m , i ≠ 5 ( 10 ⌊ n 10 ⌋ + i ) ) = g ( ∏ 1 ⩽ i ⩽ m , i ≠ 5 i ) g\left(\prod_{1\leqslant i\leqslant m,i\ne5}\left(10\lfloor\frac{n}{10}\rfloor+i\right)\right)=g\left(\prod_{1\leqslant i\leqslant m,i\ne5}i\right) g1im,i̸=5(1010n+i)=g1im,i̸=5i所以 g ( h ) g(h) g(h) 只和 m m m 有关,我们可以打表解决,而 g ( h ) ∈ { 2 , 4 , 6 , 8 } g(h)\in\{2,4,6,8\} g(h){2,4,6,8} ,所以,可以用一张表格记录 g ( h ) g(h) g(h) 在数组 lst[]={2,4,8,6} 中的下标即可(至于为什么是2486而不是2468可以联系下一段来看),具体为 lst1[]={3,3,0,3,1,1,1,2,1,3}

然后我们求解 g ( l ) = g ( h / 2 k ) = g ( lst [ lst1 [ m ] ] / 2 k ) g(l)=g(h/{2^k})=g(\text{lst}[\text{lst1}[m]]/{2^k}) g(l)=g(h/2k)=g(lst[lst1[m]]/2k)

因为 2 k 2^k 2k 是以 {2,4,8,6} 为循环节的,所以我们只要将 lst1[m] 减去 k k k 再模 4 4 4 ,就得到 g ( l ) g(l) g(l) 在数组 lst 中的下标了。此外,模 4 4 4 的时候还可以利用 x  mod  4 = ( x  mod  100 )  mod  4 x\text{ mod }4=(x\text{ mod }100)\text{ mod }4 x mod 4=(x mod 100) mod 4n%4 = = = n&3 来提高速度。

至于 g ( k ! ) g(k!) g(k!) 的递归,我们可以再制作一张表格,对应于 0 0 0 10 10 10 的阶乘末尾数字,当递归到 k &lt; 10 k&lt;10 k<10 时打表即可,表格为 {1,1,2,6,4,2,2,4,2,8}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值