• <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)  編輯 收藏 引用 所屬分類: 數學

            国产成人精品久久| 精品水蜜桃久久久久久久| 久久精品国产一区| 久久不见久久见免费视频7| 久久青青草视频| 久久只这里是精品66| 伊人精品久久久久7777| 97超级碰碰碰碰久久久久| 69国产成人综合久久精品| 一本大道加勒比久久综合| 久久精品国产男包| 91久久国产视频| 人人狠狠综合久久亚洲高清| 免费观看久久精彩视频| 97久久精品无码一区二区天美| 久久99精品久久久大学生| 少妇熟女久久综合网色欲| 久久高清一级毛片| 婷婷久久综合九色综合九七| 热RE99久久精品国产66热| 成人妇女免费播放久久久| 久久综合丝袜日本网| 成人国内精品久久久久影院| 精品久久久久久亚洲精品| 久久综合综合久久综合| 国产成人精品久久综合| 国产精品岛国久久久久| 久久96国产精品久久久| 国产精品久久久久蜜芽| 无码国内精品久久人妻蜜桃| 99久久国产综合精品成人影院| 亚洲精品无码久久毛片| 久久精品国产欧美日韩| 人妻精品久久无码区| 精品国产热久久久福利| 久久精品国产男包| 久久99热精品| 亚洲中文字幕无码久久2017| 免费国产99久久久香蕉| 久久人人添人人爽添人人片牛牛| 国产午夜久久影院|