求n得階乘得最后一位非零數字


如題,最后一位數好求,他只和最后一位相乘后的最后一位有關,唯一影響我們得是末尾0,而階乘中末尾0來自於2和5,(10得話可以看成2 * 5),所以有這個思想我們可以篩選出1 * 2 * 3 * .... * n中包含2和5得個數

如下:

int get2(int n)
{
    if(n == 0)return 0;
    return n / 2 + get2(n / 2);
}
int get5(int n)
{
    if(n == 0)return 0;
    return n / 5 + get5(n / 5);
}

解釋:

對於1 2 3 4 5 6 7 8 9 ^ 25 26 27 28 29 30
我要想找里面任何一個包含5得數字,一眼看去篩選出含有5得只有:5 10 15 20 25 30,但是有的含有兩個5啊,那我就提出一個5,把他降一個形態,然后繼續去尋找……
30 /5 = 6 得到原型 6!,其余得均為無關數,不必去管
繼續篩選1 2 3 4 5 6,這個6得階乘,是上面篩選完后產生得,可能還存在着得數,這些數將會遞歸進行二次篩選

這樣我們完成了第一步,篩選完后,你會發現原來的階乘

1 2 3 4 5 6 7 8 9 ^ 25 26 27 28 29 30

變成了

1 1 3 1 1 3 7 1 9 1 11 3 13 7 3

這樣看反而有所不大直觀,但是能夠得出得就是最后剩下得就是1 3 7 9(尾數),1沒有作用,而 3 7 9 結果觀察,他們自身得n次方得位數有個周期

1 3 9 7

1 7 9 3

1 9 1 9

所以我們就可以取尋找原來那些數含有3,5,7得個數

還是先看看原型

1 2 3 4 5 6 7 8 9 ^ 25 26 27 28 29 30

step 1對於這些數,我們要做得是奇偶分開

1 3 5 7 9 。。。 2 4 6 8 10.。。。

對於偶數唯一要做得就是抽2變型(遞歸step1)

step2 對於奇數我們可以求取了,奇數中,每10個數中肯定含有1個3,7,9,所以返回得值中有n / 10然后對於非整得數,還要考慮其最后一位得大小選擇性得+1 即+(n % 10 >= x)

然后奇數中還有5,這個根據我們得拆分,是不應該純在得所以遞歸 step 2(n/ 5 --- 抽5降形)

為什么重復step2而不是step1呢?抽了5后不會出現偶數得情況嗎??

因為 奇偶分家得時候,進來的奇數已經不再是一個完整得階乘了,但是對3 7 9 得尋找毫無影響,因為偶數都一眼找不出來,所以進來得5 是 5 15 25,降型后也是 1 3 5 .。。直接去應用step2

到此就能夠實現了

int g(int n,int x)
{
    if(n == 0)return 0;
    return n / 10 + (n % 10 >= x) + g(n / 5,x);
    //這里的5分解后只有奇數沒有偶數ggm1,3,5,7....,然后再在奇數里篩選
    //因為10,20,這樣的一開始再getx中是篩不進來得!!
}
int getx(int n,int x)//尋找這個數中
{
    if(n == 0)return 0;
    return getx(n / 2,x) + g(n,x);
}
int numtable[4][4] ={
    6,2,4,8,
    1,3,9,7,//注意順序得安排取0得時候代表有4個得時候得余數
    1,7,9,3,
    1,9,1,9
};
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        int num2 = get2(n) - get2(n-m);
        int num5 = get5(n) - get5(n-m);
        int num3 = getx(n,3) - getx(n-m,3);
        int num7 = getx(n,7) - getx(n-m,7);
        int num9 = getx(n,9) - getx(n-m,9);
        int res = 1;
        if(num5 > num2)
        {
            res = 5;
        }
        else if(num5 < num2)//WRONG 2 :只有不相等得時候才能乘法,因為numtable[0][0]也是有數據得肯定會造成影響
        {
            res *= numtable[0][(num2 - num5)%4];//WRONG 1 :乘上得是多余得2!!!
            res %= 10;
        }
        if(res != 5)
        {
            res *= numtable[1][num3%4];
            res %= 10;
            res *= numtable[2][num7%4];
            res %= 10;
            res *= numtable[3][num9%4];
            res %= 10;
        }
        printf("%d\n",res);
    }
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM