hdu 1066 Last non-zero Digit in N! (数论——n!中的最后一个非0数字)

Last non-zero Digit in N!

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

Total Submission(s): 6432    Accepted Submission(s): 1593

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

Source

South Central USA 1997

题意:求N!的最后一个非0数字。

解析:

这道题要求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}

整体思路就是这样了。

注:以上解析借鉴自:无名的博客

AC代码:

#include<stdio.h>
#include<string.h>
int mod[20]={1,1,2,6,4,2,2,4,2,8,4,4,8,4,6,8,8,6,8,2};
char n[1000];
int a[1000];
int main()
{
 int i,c,t,len;
    while(scanf("%s",n)!=EOF)
 {
  t=1;
  len=strlen(n);
  for(i=0;i<len;i++)
   a[i]=n[len-1-i]-'0';
  while(len)
  {
   len-=!a[len-1];
   t=t*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;
  }
  printf("%d\n",t);
 }
 return 0;
}
时间: 2024-12-21 06:25:21

hdu 1066 Last non-zero Digit in N! (数论——n!中的最后一个非0数字)的相关文章

hdu 1597 find the nth digit

find the nth digit Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 8356    Accepted Submission(s): 2383 Problem Description 假设: S1 = 1 S2 = 12 S3 = 123 S4 = 1234 ......... S9 = 123456789 S10 =

hdu 1247 Hat’s Words(从给的单词中找hat&#39;s word 并按字典序输出)

1.在使用mp[key]的时候它会去找键值为key的项,如果没有,他会自动添加一个key的项,再把value赋值为相应的初始值(value是int的话赋值为0,string的话赋值为空).所以如果是插入的话可以用insert,如果是查找的话可以使用find,这样可以节省开销.查找的时间复杂度为O(logn) 2. 代码: #include<iostream> #include<string> #include<map> using namespace std; stri

HDU 3518 Boring counting(后缀数组啊 求字符串中不重叠的重复出现至少两次的子串的个数)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3518 Problem Description 035 now faced a tough problem,his english teacher gives him a string,which consists with n lower case letter,he must figure out how many substrings appear at least twice,moreover

hdu 1599 find the mincost route(无向图的最小环:求从一个点遍历所有节点以后回到原点的最短路径)

在写题解之前给自己打一下广告哈~..抱歉了,希望大家多多支持我在CSDN的视频课程,地址如下: http://edu.csdn.net/course/detail/209 题目: find the mincost route Time Limit: 1000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2801    Accepted Submission(s): 1

(hdu 简单题 128道)AC Me(统计一行文本中各个字母出现的次数)

题目: AC Me Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 13465    Accepted Submission(s): 5927 Problem Description Ignatius is doing his homework now. The teacher gives him some articles and as

HDU 1800 Flying to the Mars 字典树,STL中的map ,哈希树

http://acm.hdu.edu.cn/showproblem.php?pid=1800 字典树 #include<iostream> #include<string.h> #include<stdio.h> using namespace std; struct node { int sum; node *next[10]; node() { sum=0; memset(next, NULL, sizeof(next)); }; }; int ans; char

HDU 5053 the Sum of Cube(简单数论)

http://acm.hdu.edu.cn/showproblem.php?pid=5053 题目大意: 求出A^3+(A+1)^3+(A+2)^3+...+B^3和是多少 解题思路: 设f(n)=1~n的立方和,则A^3+(A+1)^3+(A+2)^3+...+B^3=f(B) - f(A - 1) 题目给的数的范围是1~10000,1~10000立方和不会超过__int64(long long)的范围.由于是10000个数立方和. 所以可以选择打表(不知道立方和的公式,可以选择打表). 立方

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 (Java/Others) Total Submission(s): 5861    Accepted Submission(s): 1451 Problem Description The expression N!, read as "N factorial," denotes the pro

hdu 5444 Elven Postman(根据先序遍历和中序遍历求后序遍历)2015 ACM/ICPC Asia Regional Changchun Online

很坑的一道题,读了半天才读懂题,手忙脚乱的写完(套上模板+修改模板),然后RE到死…… 题意: 题面上告诉了我们这是一棵二叉树,然后告诉了我们它的先序遍历,然后,没了……没了! 反复读题,终于在偶然间注意到了这一句——"Not only that, when numbering the rooms, they always number the room number from the east-most position to the west." 它告诉我们,东边的点总是比西边的点