There are several types of factorial problems:
1. Calculate the number of 0 at the end of the factorial, divide it by 5, and accumulate.
2. How many digits are there in the result of factorial? STIRLING formula: n! ≈ SQRT (2 * pI * n) * (N/E) ^ N, takes the base-10 logarithm directly, and the integer part is the number of digits. Http://poj.org 1,423rd
3. Calculate the last non-zero bit of the factorial. This type of problem is complicated. We will focus on this issue in the topic.
First, check poj1150.
Calculate the last non-zero position of M of N.
Question Analysis: m of N is P (n, m) = n! /(N-m )!, So this is the last non-zero bit of the two factorial. We usually process the factorial one by one. First, let's take a look at the general factorial of a number N. How do we deal with non-zero digits at the end of it.
The factor of 10 is 2 and 5. These two numbers do not belong to the contraction system of the modulo 10. Therefore, we need to remove these two factors when processing the number, remove the 5 and 2 factors from all numbers.
First, we use F (n, x) to represent the number of The number of X at the end of the number less than or equal to n. N can be decomposed into 1, 3, 5, 7, 9... 2, 4, 6, 8, 10...
Because we have removed the two factors from the even number, we have actually changed them to, 9...
So we can obtain the recursive formula F (n, x) = f (n/2, x) + g (n, x), g (n, x) it indicates the number of The number of tails X in an odd number less than or equal to n.
Then how can we find G (n, x)? First, N/10 must be a part of it. Second, we need to see whether N> = x is true. If it is true, it will add 1. If it is not true, it will not. Last note, we still have the number of 5 factors in the odd number, so we need to remove the 5 factor, such as 5 15 25 35 45... after removing 5, it becomes 1 3 5 7 9 ..., therefore, g (n, x) = N/10 + (n % 10> = x) + g (N/5, X ).
With these two Recursive Formulas plus the recursive division for finding the numbers of 5 and 2 factors, we will soon be able to get the number of 2 factors, the number of 5 factors, number of 3 7 9 factors at the end. Below we will list a circular table mod2 [4] = {6, 2, 4, 8}, mod3 [4] = {1, 3, 9, 7}, mod7 [4] = {, 9, 3 }, mod9 [4] = {,} indicates the cycle section of the ending number of each factor multiplied by itself. Note that due to the contraction of 2 Non-modulo 10, SO 2 ^ 0 = 1, so pay special attention to this, so only its cyclic section does not start from 0, 0 should be processed separately. Because the factorial of N-m must be a subset of the factorial of N, We can subtract the number of factors directly.
#include <iostream>#include <cstdio>#include <cstring>using namespace std;int cnt[8];int mod2[4]={6,2,4,8};int mod3[4]={1,3,9,7};int mod7[4]={1,7,9,3};int mod9[4]={1,9,1,9};int getpow(int n,int k){int sum=0;while(n){sum+=n/k;n/=k;}return sum;}int g(int n,int k){if(n==0)return 0;return n/10+(n%10>=k)+g(n/5,k); }int get(int n,int k){if(n==0)return 0;return get(n/2,k)+g(n,k);}int main(){int n,m;while(~scanf("%d%d",&n,&m)){int res=1;memset(cnt,0,sizeof(cnt));cnt[2]=getpow(n,2)-getpow(n-m,2);cnt[5]=getpow(n,5)-getpow(n-m,5);cnt[3]=get(n,3)-get(n-m,3);cnt[7]=get(n,7)-get(n-m,7);cnt[9]=get(n,9)-get(n-m,9);if(cnt[2]>cnt[5]){res*=mod2[(cnt[2]-cnt[5])%4];}else if(cnt[2]<cnt[5]){res*=5;}res=res*mod3[cnt[3]%4]*mod7[cnt[7]%4]*mod9[cnt[9]%4];printf("%d\n",res%10);}return 0;}
Let's take a look at poj3406.
N! /(M! * (N-m )!) The last non-zero bit
Like the above question, but because the product of the factorial of M and the factorial of N-M is not a subset of the factorial of N, we can observe and find that, only the number of 3 in the factorial of N is less than the sum of the factorial of M and the factorial of N-M, in this case, we can break down the number of 9 in the N factorial. Another way is to add a loop model (I don't understand it)
#include <iostream>#include <cstdio>#include <cstring>using namespace std;int cnt[8];int mod2[4]={6,2,4,8};int mod3[4]={1,3,9,7};int mod7[4]={1,7,9,3};int mod9[4]={1,9,1,9};int getpow(int n,int k){int sum=0;while(n){sum+=n/k;n/=k;}return sum;}int g(int n,int k){if(n==0)return 0;return n/10+(n%10>=k)+g(n/5,k); }int get(int n,int k){if(n==0)return 0;return get(n/2,k)+g(n,k);}int main(){int n,m;while(~scanf("%d%d",&n,&m)){int res=1;memset(cnt,0,sizeof(cnt));cnt[2]=getpow(n,2)-getpow(n-m,2)-getpow(m,2);cnt[5]=getpow(n,5)-getpow(n-m,5)-getpow(m,5);cnt[3]=get(n,3)-get(n-m,3)-get(m,3);cnt[7]=get(n,7)-get(n-m,7)-get(m,7);cnt[9]=get(n,9)-get(n-m,9)-get(m,9);cnt[3]+=cnt[9]*2;cnt[9]=0;if(cnt[2]>cnt[5]){res*=mod2[(cnt[2]-cnt[5])%4];}else if(cnt[2]<cnt[5]){res*=5;}res=res*mod3[cnt[3]%4]*mod7[cnt[7]%4]*mod9[cnt[9]%4];printf("%d\n",res%10);}return 0;}
Finally, let's take a look at the BT question zoj1222.
This question is available in many OJ, but it is only about an order of magnitude small and can be easily AC using the above method. However, it is said that the input is a string and may contain more than 100 digits. Therefore, in the face of such high-precision large numbers, it should be solved in a new way.
The idea remains unchanged. We still take 2 and 5 as the core, and multiply the ending number of each number. It is just because of the rapid expansion of the number that we cannot use the original recursive solution, A loop section is used: int mod [10] = {,}. This indicates that the number is multiplied from 0 to 9 (5 is changed to 1) is not 0. When N is less than 5, MOD [N] is directly output. to remove the ending number 0, we need to remove 2 and 5 of the same number. We found that the number of 2 is far more than 5, and the number of factor 2 is the most, therefore, the final result must be an even number, so there is such a special ending number Division: 2/2 = 6, 4/2 =/2 = 8/2 = 4. At the same time, when dividing by the number of 2, there is still a division cycle due to the large number of 2, and the length of the cycle is 4. and the 10 tails are multiplied by 6. When n> 10, we can get a formula:
Now we can use this formula to solve the problem. It is worth noting that N is a very large number. When dividing by 5, we can use high-precision division.
#include <iostream>#include <cstdio>#include <cstring>using namespace std;char str[1001];int mod[10]={1,1,2,6,4,4,4,8,4,6};int a[1001];int getAns(int cnt){if(cnt==1&&a[0]<5)return mod[a[0]];int res=0;int w=a[0];for(int i=cnt-1;i>=0;--i){res=res*10+a[i];a[i]=res/5;res=res%5;}if(a[cnt-1]==0)--cnt;int m=(a[1]*10+a[0])%4;int tmp=getAns(cnt)*mod[w]*6%10;while(m--){if(tmp==2)tmp=6;else if(tmp==6)tmp=8;else tmp/=2;}return tmp;}int main(){while(~scanf("%s",str)){int len=strlen(str);memset(a,0,sizeof(a));for(int i=0;i<len;++i){a[i]=str[len-1-i]-'0';}int ans=getAns(len);printf("%d\n",ans);}return 0; }
4. Can the number n be expressed as the sum of several different factorial values?
In fact, this problem has nothing to do with number theory, is a problem of search http://acm.zju.edu.cn 2358th question, because N is relatively small, only may be 0 !~ 9! So you can use DFS to search directly.
#include <iostream>#include <cstdio>#include <cstring>#include <map>using namespace std;int a[10]={1,1,2,6,24,120,720,5040,40320,362880};int sum;bool vis[11];map<int,int>mymap;void dfs(int n){if(n==10){if(mymap.find(sum)==mymap.end())mymap[sum]=1;return;}sum+=a[n];dfs(n+1);sum-=a[n];dfs(n+1);}int main(){memset(vis,false,sizeof(vis));sum=0;mymap.clear();dfs(0);int n; while(~scanf("%d",&n)){ if(n<0)break;if(n==0||mymap.find(n)==mymap.end())puts("NO");else puts("YES");}return 0;}