• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 97, 文章 - 22, 評論 - 81, 引用 - 0
            數據加載中……

            HDU 1066 Last non-zero Digit in N!

            題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=1066
            /*
            題意:
                給定一個數N(N <= 10^200),求出N的階乘的最后一位非零數字。

            題解:
                找規律 + 大數模擬

            思路:
                N比較大,我一開始寫了一個log5(N)*log2(N)的算法都超時了。關鍵還是找
            規律,對于一個給定的 N,可以先將所有是5的倍數的數提出來先放在一邊不管。
            并且將原來是5的倍數的位置補上1 ,那么可以原來的序列就變成了0 1 2 3 4 1
             6 7 8 9 1,現在我們將前10個數的階乘去掉5之后的尾數列出來,得到以下
            的表data[09] = {1, 1, 2, 6, 4, 4, 4, 8, 4, 6}。我們驚人的發現第一位
            是1,最后一位是6,于是大膽的假設如果將N個數每10個分成1組(這個N個數已經
            去掉了5的倍數),每組的尾數相乘都是data[09],并且如果第一組和第二組
            都是10個元素,他們相乘的值還是6,這是顯然的。因為6*6 = 6,所以這一部分
            的乘積X[N]就可以通過N的尾數來確定,我們有如下公式:

              1. X[N] = data[N]          當N  < 10
              2. X[N] = data[N%10] * 6   當N >= 10
            其中X[N]表示1N個數中去掉所有5的倍數后的乘積。

                然后再來看5的倍數那一部分,它們是:5*10 * 15 * 20 * 25 * 30 * 35
            我們發現將他們提取公因子,可以寫成 5^P * P!。其中P = [N/5],因為求得是
            階乘最后一位非零位,所以這里的5^P必須要用P個2來匹配掉,如果將最后的非零
            為記為T[N]的話,那么T[N] = (X[N] / 2^P) * T[P]; 這里的除法不是不同意義
            的除法,因為X[N]有可能是1位數,我們發現:
            2^1 % 10 = 2,
            2^2 % 10 = 4,
            2^3 % 10 = 8,
            2^4 % 10 = 6,
            每四個一循環,當P == 0的時候比較特殊,2^P % 10 = 1
            除上2^P其實就是乘上2^(-P),這樣處理就簡單了,根據循環的性質就可以將T[N]
            簡化成T[N] = X[N] * 2^(-P) * T[P],這樣一來,算法的復雜度就只有O(log5(N))
            了。并且2是每四個一循環,2^(-P) = 2^(-P % 4 + 4)。
                計算T[N]只需要遞歸計算T[N/5]即可。
            */

            #include 
            <iostream>
            using namespace std;

            typedef __int64 ll;
            const ll Base     = (ll)100000000 * (ll)1000000000;

            ll val_pro[
            20];
            ll carry_pro[
            5];

            int TwoMod[] = {2486};
            // 將5的倍數部分補1后的階乘尾數
            int data[] = {1126444846};

            struct BigNum {
                ll nData[
            14];
                
            int nLen;

                BigNum()
            {nLen = 0;}
                BigNum(
            char *str);

                
            int  ModFour();
                
            int  ModTen();
                
            void DivideFive();
                
            void DivideTwo();

                
            bool operator==(BigNum b) {
                    
            if(nLen != b.nLen) return false;
                    
            int i;
                    
            for(i = 0; i < nLen; i++{
                        
            if(nData[i] != b.nData[i])
                            
            return false;
                    }

                    
            return true;
                }


                
            void print(){
                    printf(
            "%d",nLen==0?0:nData[nLen-1]);
                    
            for(int i=nLen-2;i>=0;i--)
                        
            for(ll j=Base/10;j>0;j/=10)
                            printf(
            "%d",nData[i]/j%10);
                    puts(
            "");
                }


            }
            ;

            BigNum::BigNum(
            char *S) {
                
            int i, j = 0;
                nData[nLen 
            = 0= 0;
                
            for (i = strlen(S)-1; i >= 0--i) {
                    nData[nLen] 
            += (S[i] - '0'* val_pro[j];
                    
            ++j;
                    
            if (val_pro[j] >= Base) j = 0, nData[++nLen] = 0;
                }

                
            if (nData[nLen] > 0++nLen;
            }


            int BigNum::ModFour() {
                
            if(!nLen)
                    
            return 0;
                
            return nData[0% 4;
            }

            int BigNum::ModTen() {
                
            if(!nLen)
                    
            return 0;
                
            return nData[0% 10;
            }


            void BigNum::DivideFive() {
                
            if(!nLen)
                    
            return ;
                
            int i;
                
            for(i = nLen-1; i >= 0--i) {
                    
            int nCarry = (nData[i] % 5);
                    nData[i] 
            /= 5;
                    
            if(nCarry && i) {
                        nData[i
            -1+= carry_pro[ nCarry ];
                    }

                }

                
            if(!nData[nLen-1])
                    
            -- nLen;

                
            return ;
            }


            void BigNum::DivideTwo() {
                
            if(!nLen)
                    
            return ;
                
            int i;
                
            for(i = nLen-1; i >= 0; i--{
                    
            int nCarry = (nData[i] & 1);
                    nData[i] 
            >>= 1;
                    
            if(i && nCarry) {
                        nData[i
            -1+= Base;
                    }

                }

                
            if(!nData[nLen-1])
                    
            -- nLen;
                
            return ;
            }



            int FindNoneZeroTail(BigNum Bn) {
                
            if(!Bn.nLen)
                    
            return 1;
                
            if(Bn.nLen == 1{
                    
            if(Bn.nData[0< 5{
                        
            return data[ Bn.nData[0] ];
                    }
            else if(Bn.nData[0< 10){
                        
            return data[ Bn.nData[0] ] * TwoMod[2% 10;
                    }

                }


                
            int v = Bn.ModTen();
                Bn.DivideFive();

                
            int XN = data[v] * 6 % 10;
                
            int idx = 4 - Bn.ModFour();
                
            if(idx == 0{
                    idx 
            = 4;
                }

                XN 
            *= TwoMod[idx - 1];
                
            return XN * FindNoneZeroTail(Bn) % 10;
            }



            char str[10000];

            int main() {
                
            int i, j;
                val_pro[
            0= 1;
                
            for(i = 1; i < 20; i++)
                    val_pro[i] 
            = val_pro[i-1* 10;
                
            for(i = 0; i < 5; i++)
                    carry_pro[i] 
            = i * Base;

                
            while(scanf("%s", str) != EOF) {
                    BigNum X(str);
                    printf(
            "%d\n", FindNoneZeroTail(X));
                }


                
            return 0;
            }


            posted on 2011-04-11 12:11 英雄哪里出來 閱讀(2478) 評論(0)  編輯 收藏 引用 所屬分類: 數學

            国产成人精品久久综合 | 国产香蕉久久精品综合网| 久久这里有精品视频| 久久精品国产免费观看| www久久久天天com| 久久涩综合| 69SEX久久精品国产麻豆| 精品久久久久久久久久久久久久久| 美女久久久久久| 久久精品国产半推半就| 伊人久久大香线蕉无码麻豆| 久久久一本精品99久久精品88 | 一本久久a久久精品亚洲| 日本精品久久久久中文字幕| 久久综合伊人77777麻豆| 久久精品嫩草影院| 色婷婷综合久久久久中文一区二区| 精品久久久久久国产三级| 日韩精品久久久肉伦网站| 香蕉99久久国产综合精品宅男自 | 少妇久久久久久被弄到高潮| 国产国产成人精品久久| 欧美日韩精品久久免费| 日本精品久久久久中文字幕8 | 99久久久国产精品免费无卡顿| 亚洲国产综合久久天堂| 久久精品国产第一区二区| 日本福利片国产午夜久久| 99国产欧美精品久久久蜜芽| 亚洲女久久久噜噜噜熟女| 久久夜色精品国产噜噜亚洲a| 国产精品午夜久久| 久久免费视频网站| 久久精品国产亚洲麻豆| 国产精品99久久99久久久| 色婷婷综合久久久久中文| 婷婷综合久久中文字幕蜜桃三电影 | 国产精品99久久久久久www| 久久99精品国产麻豆宅宅| 韩国无遮挡三级久久| 久久综合狠狠色综合伊人|