HDU-1066 Last non-zero Digit in N!

本文介绍了一种求解n的阶乘(n!)最后一个非零数字的高效算法。该算法利用数学规律,通过构建特殊表格并结合递归方法,实现了O(log5(N))的时间复杂度。适用于快速计算大数阶乘的尾数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意: 求n的阶乘 n! 的最后一个非0数 如:5!=120 所以答案是2

解析:

先考虑简单的。考虑某一个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即可。整个算法相当巧妙,写起来也比较轻松。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

#define N 10005
char a[N];
int b[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 solve()
{
   int i,j,k,len,res;
   len=strlen(a);
   res=1;
   for(i=0;i<len;i++) b[i]=a[len-1-i]-'0';
   if(len==1) return m[b[0]];
   while(len)//递归调用
   {
       k=0;
       len-=!(b[len-1]);
       res=res*m[b[1]%2*10+b[0]]%10; //只有最后的尾数有用
       for(i=len-1;i>=0;i--) // n/5
       {
           k=k*10+b[i];
           b[i]=k/5; //商
           k=k%5;  //余数
       }
   }
   return res;
}
int main()
{
    while(~scanf("%s",&a))
      printf("%d\n",solve());
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值