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=1∏k5i×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=2k1⎝⎛i=0∏⌊10n⌋−11⩽j⩽9,j̸=5∏(10i+j)⋅1⩽i⩽m,i̸=5∏(10⌊10n⌋+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 5∤ti,∀1⩽i⩽s,则 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=1∏sti)=g(i=1∏s(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
g⎝⎛i=0∏⌊10n⌋−11⩽j⩽9,j̸=5∏(10i+j)⎠⎞=g⎝⎜⎛⎝⎛1⩽j⩽9,j̸=5∏j⎠⎞⌊10n⌋⎠⎟⎞=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)
g⎝⎛1⩽i⩽m,i̸=5∏(10⌊10n⌋+i)⎠⎞=g⎝⎛1⩽i⩽m,i̸=5∏i⎠⎞所以
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 4 和 n%4
=
=
= n&3
来提高速度。
至于
g
(
k
!
)
g(k!)
g(k!) 的递归,我们可以再制作一张表格,对应于
0
0
0 到
10
10
10 的阶乘末尾数字,当递归到
k
<
10
k<10
k<10 时打表即可,表格为 {1,1,2,6,4,2,2,4,2,8}
。