p; }
while (cin >> num)
{
printf("%5d -> %d\n", num, ans[num]);
}
return 0;
}
(3)编程思路2。
下面换一个思路来求得N!的最后一个非0的数字。由于质因数2和5组合之后会使得N!末尾产生0。因此,可以将1~N序列中的质因数2和5全部去掉(当然2的个数比5的个数要多,所以需在最后考虑多余的2对末位的影响)。例如,计算10!的最后一个非0的数字,将1*2*3*4*5*6*7*8*9*10序列中去掉2、5 因子后,就是1*1*3*1*1*3*7*1*9*1(去掉的因子2有8个,5有2个)。由于2、5因子已经被去除,那么剩下的数的末位数字一定是1、3、7、9中四者之一。然后再求出这么一串数末位相乘以后的末位数字是7,最后再补上6个2(末位为4)对末位的影响,得到结果8。
因此,按这种思路求解的关键是求得1~N序列中质因数2和5的个数,分别去掉2和5因子后的N个数中末位数字分别是3、7、9的数的个数。由于N!是在(N-1)!的基础上乘以N,因此,在统计N!的情况时可以在(N-1)的基础上进行。
可定义一个二维数组int table[10][10001],其中元素table[2][n]和table[5][n]分别表示在n!中质因子2和5的个数,table[3][n]、table[7][n]和table[9][n]分别表示在1~n这n个数(分别去掉了2和5因子)中末位数字为3、7、9的数的个数。其余的的数组元素不用即可。
由于只需考虑2、5因子个数和末位3、7、9的个数这5种情况,二维数组table[10][10001]有一半的元素没有使用,为节省存储空间,可以定义数组为int table[5][10001],其中元素table[0][n]表示在n!中质因子2的个数,table[2][n](即table[(5-1)/2])t表示在n!中质因子5的个数,able[1][n]、table[3][n]和table[4][n]分别表示在1~n这n个数(分别去掉了2和5因子)中末位为3、7、9的数的个数。设数字为i,则这三种情况可以统一表示为table[(i-1)/2]。
数组table的值预先求好后,N!的最后一个非0的数字就容易求得了,只需求得table[0][n]-table[2][n]个2(质因子2比5多的个数)、table[1][n]个3、table[3][n]个7和table[4][n]个9相乘所产生的末位数字即可。
实际上,末位数字为2、3、7、9的数的n次方的末位数字是有规律的,周期可统一为4。例如,2的n次方的末位数字依次为2、4、8、6、2、4、8、6、…;3的n次方的末位数字依次为3、9、7、1、3、9、7、1、…;7的n次方的末位数字依次为7、9、3、1、…;9的n次方的末位数字依次为9、1、9、1、…。因此,可以定义一个二维数组
int last[4][4] ={{6,2,4,8},{1,3,9,7},{1,7,9,3},{1,9,1,9}};
用于保存数字2、3、7、9的末位数字的循环出现情况,这样k个2、3、7、9相乘产生的末位直接查表就可以了。例如,19个3相乘产生的末位数字为last[1][19%4]=last[1][3]=7。要注意一个特殊情况,0个2的末位为1。
(4)源程序2。
#include<iostream>
using namespace std;
int main()
{
int table[5][10001],i,t,n,cnt2,cnt5,cnt3,cnt7,cnt9;
int last[4][4] ={{6,2,4,8},{1,3,9,7},{1,7,9,3},{1,9,1,9}};
table[0][1]=table[1][1]=table[2][1]=table[3][1]=table[4][1]=0;
for (i=2;i<=10000;i++)
{
t=i;
cnt2=cnt5=0;
while (t%2==0)
{
cnt2++;
t=t/2;
}
while (t