階乘末尾連續零的個數


十進制中 N! 末尾連續零的個數

  1. 首先考慮 800 中有兩個連續的零,800=\(8*10^2\)

    首先考慮 50 中有一個連續的零,50= \(5*10^1\)

    從上面可以看出,N! = \(a*10^k\) , 那么 N! 末尾就有 \(k\) 個連續的零

  2. 由質因數分解唯一定理,10 可以分解為小於10的質數乘積,即 10=2*5

    所以我們只要統計出現 2,5的次數,取其中最小的即是末尾連續的零的個數

    統計方法:

    可以看出 2*5 產生一個0, 4*25產生兩個零,8*125產生三個零,依次類推

    例如:計算 2015! 中有多少連續的零
    第一步,計算1到2015里多少個5,25,125,625
    1、2015÷5=403 記作A1;
    2、2015÷25=80.6取整得80 記作A2;
    3、2015÷125=16.12取整得16 記作A3;
    4、2015÷625=3.224取整得3 記作A4;
    第二步,計算上述A1到A4中重復的部分
    1、能被5整除的數里包含的能被25整除的數,記作B1
    B1=A1-A2=403-80=323;
    2、能被25整除的數里包含的能被125整除的數,記作B2
    B2=A2-A3=80-16=64;
    3、能被125整除的數里包含的能被625整除的數,記作B3
    B3=A3-A4=16-3=13;
    4、能被625整除的數里沒有重復其它情況,直接計入結果,記作B4
    B4=A4;
    第三步,最終結果是
    B11+B22+B33+B44=323+128+39+12=502.........(1)
    另一種方法:
    2015÷5+2015÷25+2015÷125+2015÷625=403+80+16+3=502。。。。。(2)

    (1) (2)式子思路完全不同

    (1)還需要使用容斥原理的知識去掉重復的部分

    (2)式子為什么可以這么計算?

    可以理解為,在計算 5 的個數時候,包含了 5 25, 125, 625

    在計算25的個數時候,包含了 25 125 625

    在計算125的個數時候,包含了125 625

    在計算625的個數時候,包含了625

    最終,5 計算一次,25計算2次,125計算3次,625計算4次

    從上面可以看出來,計算零的個數時候, \(5*1+25*2+125*3+625*4\)

    正好和上面每次包含的數量是一致的,一次可以得到正確結果

    對(2)的代碼實現

    //一種方法
    
    
    int cnt_R_10_1(int n){
    	int ans=0,mult=5;
    	while(mult<=n){
    		ans+=n/mult;
    		mult*=5;
    	}
    	return ans;
    }
    
    //另一種方式,乘法的逆向思維
    int cnt_R_10_2(int n){
    	int ans=0;
    	while(n){
    		ans+=n/5;
    		n/=5;
    	}
    	return ans;
    }
    
    

M進制中 N! 末尾連續零的個數

  1. 有上面的例子我們可以推出

  1. 實現代碼
#include "../common.h"
const int MAXN = 100;

//素數表
int prime[MAXN]={2};
//保存 alpha
int ind[MAXN]={0};
//保存 alpha·k 的乘積
int cnt[MAXN]={0};

//一種方式
int cnt_R_10_1(int n){
	int ans=0,mult=5;
	while(mult<=n){
		ans+=n/mult;
		mult*=5;
	}
	return ans;
}

//另一種方式,乘法的逆向思維
int cnt_R_10_2(int n){
	int ans=0;
	while(n){
		ans+=n/5;
		n/=5;
	}
	return ans;
}


void init(){
	int k=1;
	for(int i=3;i<=MAXN;i+=2){
		int flag=0;
		for(int j=2;j*j<=i;j++){
			if(i%j==0){
				flag=1; break;
			}
		}
		if(!flag)
			prime[k++]=i;
	}
}


//求 alpha·k 的乘積
int getcnt(int x, int p){
	int ans = 0;
	while(x){
		ans+=x/p;
		x/=p;
	}
	return ans;
}

int cnt_R_M(int n,int M){
	init();

	//看 M 可以被哪些質數分解
	for(int i=0;i<MAXN;i++){
		if(prime[i]){
			while(M % prime[i]==0){
			ind[prime[i]]++;
			M /= prime[i];
			}
		}		
	}


	for(int i=0;i<MAXN;i++){
		if(ind[i]) cnt[i]=getcnt(n,i);
	}

	int ans=1e8;
	for(int i=0;i<MAXN;i++){
		if(cnt[i]) ans=min(ans,cnt[i]/ind[i]);
	}

	return ans;

}


int main(int argc, char const *argv[])
{
	//求解十進制下 N! 中末尾連續零
	// cout<<"1: "<<cnt_R_10_1(2015)<<endl;
	// cout<<"2: "<<cnt_R_10_2(2015)<<endl;


	//2015! 在 M 進制下末尾連續零
	cout<<cnt_R_M(2015,10)<<endl;
	return 0;
}


免責聲明!

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



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