• <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
            數(shù)據(jù)加載中……

            HDU 1066 Last non-zero Digit in N!

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

            題解:
                找規(guī)律 + 大數(shù)模擬

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

              1. X[N] = data[N]          當(dāng)N  < 10
              2. X[N] = data[N%10] * 6   當(dāng)N >= 10
            其中X[N]表示1N個(gè)數(shù)中去掉所有5的倍數(shù)后的乘積。

                然后再來看5的倍數(shù)那一部分,它們是:5*10 * 15 * 20 * 25 * 30 * 35
            我們發(fā)現(xiàn)將他們提取公因子,可以寫成 5^P * P!。其中P = [N/5],因?yàn)榍蟮檬?br>階乘最后一位非零位,所以這里的5^P必須要用P個(gè)2來匹配掉,如果將最后的非零
            為記為T[N]的話,那么T[N] = (X[N] / 2^P) * T[P]; 這里的除法不是不同意義
            的除法,因?yàn)閄[N]有可能是1位數(shù),我們發(fā)現(xiàn):
            2^1 % 10 = 2,
            2^2 % 10 = 4,
            2^3 % 10 = 8,
            2^4 % 10 = 6,
            每四個(gè)一循環(huán),當(dāng)P == 0的時(shí)候比較特殊,2^P % 10 = 1
            除上2^P其實(shí)就是乘上2^(-P),這樣處理就簡單了,根據(jù)循環(huán)的性質(zhì)就可以將T[N]
            簡化成T[N] = X[N] * 2^(-P) * T[P],這樣一來,算法的復(fù)雜度就只有O(log5(N))
            了。并且2是每四個(gè)一循環(huán),2^(-P) = 2^(-P % 4 + 4)。
                計(jì)算T[N]只需要遞歸計(jì)算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的倍數(shù)部分補(bǔ)1后的階乘尾數(shù)
            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)  編輯 收藏 引用 所屬分類: 數(shù)學(xué)

            久久婷婷五月综合成人D啪| 久久综合久久美利坚合众国| 久久99久久99精品免视看动漫 | 亚洲精品久久久www| 91精品免费久久久久久久久| 97久久精品国产精品青草| 99久久久国产精品免费无卡顿| 久久亚洲高清观看| 九九精品久久久久久噜噜| 久久精品成人影院| 久久久久久久97| 久久久噜噜噜久久中文字幕色伊伊 | 伊人久久大香线蕉精品不卡 | 久久久久久久女国产乱让韩| 2021国产精品久久精品| 久久亚洲精品国产精品婷婷| 精品国产乱码久久久久久1区2区| 久久中文骚妇内射| 久久影视综合亚洲| 精品国产乱码久久久久久1区2区 | 国产成人精品久久亚洲高清不卡 | 亚洲人成无码久久电影网站| 欧美午夜A∨大片久久| 久久精品这里热有精品| 日本一区精品久久久久影院| 久久国产V一级毛多内射| 亚洲国产精品久久久天堂| 久久免费99精品国产自在现线 | 青青热久久综合网伊人| 国产三级观看久久| 久久这里只有精品首页| 精品综合久久久久久888蜜芽| 久久综合久久综合九色| 亚洲乱码日产精品a级毛片久久 | 麻豆精品久久久一区二区| 久久免费香蕉视频| 久久综合88熟人妻| 久久www免费人成看国产片| 无码超乳爆乳中文字幕久久| 成人a毛片久久免费播放| 久久精品国产亚洲AV香蕉|