1 题意
求
n
!
n!
n!最右边的非零数字。
链接:link
2 思路
已知
n
!
=
1
×
2
×
3
×
…
×
(
n
−
2
)
×
(
n
−
1
)
×
n
n!=1×2×3×…×(n-2)×(n-1)×n
n!=1×2×3×…×(n−2)×(n−1)×n。
以
5
5
5为长度对
n
!
n!
n!划分,
(
1
×
2
×
3
×
4
×
5
)
×
(
6
×
7
×
8
×
9
×
10
)
×
(
11
×
12
×
13
×
14
×
15
)
×
…
×
r
(1 \times 2 \times 3 \times 4 \times 5) \times(6 \times 7 \times 8 \times 9 \times 10) \times(11 \times 12 \times 13 \times 14 \times 15) \times \ldots \times r
(1×2×3×4×5)×(6×7×8×9×10)×(11×12×13×14×15)×…×r。
每一块去掉一个
2
2
2和一个
5
5
5,对结果没有影响。
(
1
×
2
×
3
×
4
×
1
)
2
×
(
6
×
7
×
8
×
9
×
2
)
2
×
(
11
×
12
×
13
×
14
×
3
)
2
×
…
×
r
\frac{(1 \times 2 \times 3 \times 4 \times 1)}{2} \times \frac{(6 \times 7 \times 8 \times 9 \times 2)}{2} \times \frac{(11 \times 12 \times 13 \times 14 \times 3)}{2} \times \ldots \times r
2(1×2×3×4×1)×2(6×7×8×9×2)×2(11×12×13×14×3)×…×r
取出每一组的最后一个数字。
⌊
n
5
⌋
!
×
(
1
×
2
×
3
×
4
)
2
×
(
6
×
7
×
8
×
9
)
2
×
(
11
×
12
×
13
×
14
)
2
×
…
×
r
\lfloor\frac{n}{5}\rfloor ! \times \frac{(1 \times 2 \times 3 \times 4)}{2} \times \frac{(6 \times 7 \times 8 \times 9)}{2} \times \frac{(11 \times 12 \times 13 \times 14)}{2} \times \ldots \times \mathrm{r}
⌊5n⌋!×2(1×2×3×4)×2(6×7×8×9)×2(11×12×13×14)×…×r
此时,每一组对
10
10
10取余都等于
2
2
2,可将上式化简。
⌊
n
5
⌋
!
×
2
⌊
n
5
⌋
×
r
\lfloor\frac{n}{5}\rfloor ! \times 2^{\lfloor\frac{n}{5}\rfloor} \times r
⌊5n⌋!×2⌊5n⌋×r
每一组数中只有最后一个数能被
5
5
5整除,所以
r
r
r一定不能被
10
10
10整除,可以直接对其取余。
由于
n
%
10
=
5
n\%10=5
n%10=5和
n
%
10
=
0
n\%10=0
n%10=0没有余项,余项值暂定为
1
1
1。
r
%
10
r\%10
r%10以
10
10
10为循环节,
n
%
10
n\%10
n%10与
r
%
10
r\%10
r%10的关系如下表所示。
n % 10 n\%10 n%10 | r % 10 r\%10 r%10 |
---|---|
0 | 1 |
1 | 1 |
2 | 2 |
3 | 6 |
4 | 4 |
5 | 1 |
6 | 6 |
7 | 2 |
8 | 6 |
9 | 4 |
2 n % 10 2^{n}\%10 2n%10以 4 4 4为循环节, n ≥ 1 n≥1 n≥1。 n % 4 n\%4 n%4与 2 n % 10 2^{n}\%10 2n%10的关系如下表所示。
n % 4 n\%4 n%4 | 2 n % 10 2^{n}\%10 2n%10 |
---|---|
0 | 6 |
1 | 2 |
2 | 4 |
3 | 6 |
因为 r % 10 r\%10 r%10以 10 10 10位循环节, 2 n % 10 2^{n}\%10 2n%10以 4 4 4为循环节,所以 ( r × 2 n ) % 10 (r \times 2^{n})\%10 (r×2n)%10以 20 20 20,其中 n ≥ 1 n≥1 n≥1。 n % 20 n\%20 n%20与 ( r × 2 n ) % 10 (r \times 2^{n})\%10 (r×2n)%10的关系如下表所示。
n % 20 n\%20 n%20 | ( r × 2 n ) % 10 (r \times 2^{n})\%10 (r×2n)%10 |
---|---|
0 | 1 |
1 | 1 |
2 | 2 |
3 | 6 |
4 | 4 |
5 | 2 |
6 | 2 |
7 | 4 |
8 | 2 |
9 | 8 |
10 | 4 |
11 | 4 |
12 | 8 |
13 | 4 |
14 | 6 |
15 | 8 |
16 | 8 |
17 | 6 |
18 | 8 |
19 | 2 |
当
n
=
0
n=0
n=0时
(
r
×
2
n
)
%
10
=
1
(r \times 2^{n})\%10=1
(r×2n)%10=1,也满足上述表格。
事先将
(
r
×
2
n
)
%
10
(r \times 2^{n})\%10
(r×2n)%10对
n
%
20
n\%20
n%20的映射值存储在
m
[
]
m[]
m[]数组中,则
L
N
D
(
n
)
=
L
N
D
(
⌊
n
5
⌋
)
×
m
[
n
%
20
]
%
10
\mathrm{LND}(\mathrm{n})=\mathrm{LND}\left(\lfloor\frac{n}{5}\rfloor\right) \times m[\mathrm{n} \% 20] \% 10
LND(n)=LND(⌊5n⌋)×m[n%20]%10。
2.1 时间复杂度分析
根据递推式可知,递归或循环求解只需要 O ( log ( n ) ) \mathcal{O}(\log(n)) O(log(n))的时间,由于除 5 5 5也需要 O ( log ( n ) ) \mathcal{O}(\log(n)) O(log(n))的时间,所以时间复杂度为 O ( log 2 ( n ) ) \mathcal{O}(\log^{2}(n)) O(log2(n))。
2.2 实现
2.2.1 递归实现
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e3+10;
int m[20]={1,1,2,6,4,2,2,4,2,8,4,4,8,4,6,8,8,6,8,2};
char buf[N],bufLen;
int num[N],numLen;
int lastdigit(){
if(numLen==0) return 1;
int res=m[num[1]%2*10+num[0]]%10;//对20取余
for(int c=0,i=numLen-1;i>=0;i--){
c=c*10+num[i],num[i]=c/5,c%=5;//除5
}
if(!num[numLen-1]) numLen--;
return lastdigit()*res%10;
}
int main(){
while(~scanf("%s",buf)){
bufLen=strlen(buf);
for(int i=0;i<bufLen;i++) num[i]=buf[bufLen-1-i]-'0';
numLen=bufLen;
printf("%d\n",lastdigit());
}
return 0;
}
2.2.2 非递归实现
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e5+10;
char str[N],a[N];
int m[20]={1,1,2,6,4,2,2,4,2,8,4,4,8,4,6,8,8,6,8,2};
int lastdigit(char *buf){
int len=strlen(buf),ret=1;
if(len==1) return m[buf[0]-'0'];
for(int i=0;i<len;i++) a[i]=buf[len-1-i]-'0';
for(;len;len-=!a[len-1]){
ret=ret*m[a[1]%2*10+a[0]]%5;//对20取余
for(int c=0,i=len-1;i>=0;i--){
c=c*10+a[i],a[i]=c/5,c%=5;//除5
}
}
return ret+ret%2*5;
}
int main(){
while(~scanf("%s",str)){
printf("%d\n",lastdigit(str));
}
return 0;
}