1. 程式人生 > >hdu 1066 Last non-zero Digit in N! 數學,求n!最後一位非零數

hdu 1066 Last non-zero Digit in N! 數學,求n!最後一位非零數

題意:求n!的最後一位非零數。(n很大,需要字元輸入)

題解:

我們發現n!末尾的0都是通過5和2想成得到的,我們將n分成20個數一組,最後剩下不足20個數。我們來討論【1-20】這20個數中含有5的數,只有5,10,15,20是5的倍數,我們還要找4個2來使之乘積得到10(我們從4和12中取,4取了後剩餘1,12取了後剩下3),那麼剩下數乘積的尾數就是所有尾數的乘積%10了(5的倍數的剩餘數先不管),最後剩餘的乘積是6,;再討論【21-40】,5個倍數是25,30,35,40,那麼我們取2來自24和32,同樣最後剩餘的尾數值是6。,以此類推最後每20個數剩餘的尾數都是6。我們記這次的操作為fun(n),那麼最後要求的尾數6^(n/20)*fun(n/5)*不足20個的尾數。

其中fun(n/5)是5的倍數除掉一個5後剩餘的數,正好構成1~n/5,正好是一個遞迴;而6^(n/20)的尾數是6(6乘以6尾數還是6);而不足20個的數,我們可以預處理出來(預處理的時候要注意5的倍數也要處理,因為fun(n/5)包含了這裡的5的倍數)。除了1以外,其他結果都是偶數,那麼乘以6的尾數是不變的。。可以忽略掉

程式碼:

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <ctime>
#include <vector>
#include <cmath>
#include <cstdlib>
using namespace std;

const int maxn=1e3+10;
int f[20]={1,1,2,6,4,2,2,4,2,8,4,4,8,4,6,8,8,6,8,2};
char a[maxn];
int c[maxn];
int main()
{
    while(scanf("%s",a)!=EOF)
    {
        int i,j,k,n,ans=1,t;
        n=strlen(a);
        for(i=0;i<n;i++)
            c[n-1-i]=a[i]-'0';
        while(n>1)
        {
            while(c[n-1]==0)n--;
            ans=ans*f[c[1]%2*10+c[0]]%10;
            t=0;
            for(i=n-1;i>=0;i--)//num=num/5;
            {
                t=t*10+c[i];
                c[i]=t/5;
                t=t%5;
            }
        }
        printf("%d\n",ans*f[c[0]]%10);
    }
    return 0;
}