The last non-zero digit in N![hdu-1066]

这道题被搁置了很久,又拿来做,终于搞懂了。

分析:

1.末尾的0是由2和5相乘产生的,而2的个数多于5的个数。

2.将5的倍数提取出来:令An为提取后的结果,函数f(x)表示x的最右非0位,N! = 5 * (floor(N/5)!) * An, f(N!) = f(floor(N/5)!)*f(5*An);

显然这是一个递归式,那么怎样求 f(5*An)?

易知,An中没有末尾0,则只需在An中提取出相应个数的2,即An除以相应个数的2。

处理出前100(A0 ~ A99 除以相应个数的2):

 

 

  
    
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
20: 6
21: 6
22: 2
23: 6
24: 4
25: 2
26: 2
27: 4
28: 2
29: 8
30: 4
31: 4
32: 8
33: 4
34: 6
35: 8
36: 8
37: 6
38: 8
39: 2

40 : 6
41 : 6
42 : 2
43 : 6
44 : 4
45 : 2
46 : 2
47 : 4
48 : 2
49 : 8
50 : 4
51 : 4
52 : 8
53 : 4
54 : 6
55 : 8
56 : 8
57 : 6
58 : 8
59 : 2    

 

 

规律是很明显的。因为N可能很大,需要用大数除法计算N/5。

代码
   
     
#include < stdio.h >
#include
< string .h >
#define MAXN 10000

char n[ 10000 ];

int lastdigit( char * buf)
{
const int mod[ 21 ] = { 6 , 6 , 2 , 6 , 4 , 2 , 2 , 4 , 2 , 8 , 4 , 4 , 8 , 4 , 6 , 8 , 8 , 6 , 8 , 2 , 1 };
int len = strlen(buf),a[MAXN],i,c,ret = 1 ;
if (len == 1 ) return mod[(buf[ 0 ] - ' 0 ' ) <= 1 ? 20 :(buf[ 0 ] - ' 0 ' )];
for (i = 0 ;i < len;i ++ ) a[i] = buf[len - 1 - i] - ' 0 ' ;
for (;len;len -=! a[len - 1 ])
{
ret
= ret * mod[a[ 1 ] % 2 * 10 + a[ 0 ]] % 10 ;
for (c = 0 ,i = len - 1 ;i >= 0 ;i -- )
c
= c * 10 + a[i],a[i] = c / 5 ,c %= 5 ;
}
return ret;
}


int main()
{
while (scanf( " %s " ,n) != EOF)
printf(
" %d\n " ,lastdigit(n));
return 0 ;
}

 

你可能感兴趣的:(zero)