階乘問題 【數論】
題目來源
洛谷1134 https://www.luogu.org/problemnew/show/P1134
題目簡述
求 N!中最右側第一個非零項 (命名為有效位)
輸入輸出格式
輸入格式:
僅一行包含一個正整數 NN 。
輸出格式:
一個整數,表示最右邊的非零位的值。
分析
對於任意 N>1
有效位只能為 2,4,6,8
觀察這幾個數之間的連系(我的著手點為2進制)
2=2
4=2x2
8=2x2x2
6=2x2x2x2 (有效位)
2=2x2x2x2x2
4=2x2x2x2x2x2
......
那麽可以得到
在這四個數中,
任意數 x6 得到其本身
任意數 x8 等價於減少一個 x2 (2=2x2x2x2x2)
接著,對於所有存在的個位數字 (因為需要排除個位為零導致十位數字參與運算的幹擾,排除數字5,0)
1x2x3x4x6x7x8x9=6 (72576有效位為6)
而根據前文分析 ,x6是只會無意義的
所以對於 10*(k+1)>N>10*k 時 (1~10*k) 的相乘是無意義的
即我們只需要計算 N的個位相乘
最後再看我們先前忽略的幹擾數字:
0 無法帶來任何改變 ,忽略
5 對於 2x2x2x..x2 的一個數來說 x5 等價於減少一個 x2 ,也就是說 x5 等價於 x8 (我們這麽做的目的是為了排除x5所導致對十位數字的計算)。而因為1~N中因數5的系數是連續的(例如N=32 具有1x5,2x5,3x5,4x5,5x5,6x5 共6(32/5)個5需要特殊處理,且其中系數1,2,3,4,5,6是連續且需要計算的,運算過程直接當成 N=6算即可)
1 #include<queue> 2 #include<cstdio> 3 #include<cstring> 4CODE#include<iostream> 5 #include<algorithm> 6 using namespace std; 7 int N; 8 void Read(int &x){ 9 x=0; 10 char c=getchar(); 11 while(!isdigit(c)) c=getchar(); 12 while(isdigit(c)) x=x*10-‘0‘+c,c=getchar(); 13 return ; 14 } 15 void Write(int x){ 16 int np=0; 17 int s[505]; 18 while(x) s[++np]=x%10,x/=10; 19 while(np) putchar(s[np--]+‘0‘); 20 putchar(‘\n‘); 21 return ; 22 } 23 int E[4]={6,8,4,2}; //乘8的有效位(以4為周期的數列) 24 int main(){ 25 Read(N); 26 int ans=1; 27 while(N){ 28 for(int i=1;i<=(N%10);i++) 29 if(i!=5) ans=(ans*i)%10; 30 N/=5; //計算特殊處理的5 和 這些5的系數 31 ans=(ans*E[N%4])%10; 32 } 33 Write(ans); 34 return 0; 35 }
階乘問題 【數論】