题意:求nPm,即n个元素的m中排列方式结果中末尾非0 的数字。
思路: 首先我们知道,2和5相乘末尾非0数字为1,相当于可以相消。我们先把这两个因子抽离出来,考虑末尾为3,7,9的数字。
设f(n,x)为:n!因子中,抽离了2,5,后末尾数字为x的因子个数。分析可以知道f(n,x)=f(n/2,x)+g(n,x); g(n,x)表示n!中所有奇因子末尾数字为x的因子个数。
可以这样分析,对于n!的每一个因子k,如果k是偶数则除二纳入到f(n/2,x)中,如果k是奇数则到g(n,x)中,这样就有了上面那条式子。
接下来分析g(n,x),显然n/10肯定是要的,因为以10为周期,肯定包含3,7,9中的一个,如果n%10>=x,那么加1,还要加上因子中抽离5后的数g(n/5,x)。
所以g(n,x)=n/10+(n%10>=x)+g(n/5,x);
对于2,5的因子个数可以这样求,getx(n,x),x=2,5,getx(n,x)=getx(n/x,x)+n/x;
现在要算的是n!/m!的结果,因为结果肯定是整数,所以因子个数可以直接相减,
把2,3,5,7,9的数目求出来后,要比较2,5因子个数谁多,2多就要减去5的(相消),相等就两个都不要,5多就要乘以5.
剩下3,7,9因子指数相乘时有个循环节,mod3[4]={1,3,9,7};mod7[4]={1,7,9,3};mod9[4]={1,9,1,9};
看有多少个因子数直接可以得出cnt个x的因子相乘的末尾数。
#include <iostream> #include <cmath> #include <stdio.h> #include <map> #include <string> #include <string.h> #include <algorithm> #include <queue> using namespace std; #define REP(i,a,b) for(int i=a;i<b;++i) #define scan(a) scanf("%d",&a) #define maxn 500005 #define mset(a,b) memset(a,b,sizeof a) #define LL long long int g(int n,int x) { if(!n) return 0; return n/10+(n%10>=x)+g(n/5,x); } int f(int n,int x) { if(n==0) return 0; return f(n/2,x)+g(n,x); } int getx(int n,int x) { if(n<x) return 0; return n/x+getx(n/x,x); } 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 main() { int n,m; int cnt[10]; while(cin>>n>>m) { m=n-m; cnt[2]=getx(n,2)-getx(m,2); cnt[3]=f(n,3)-f(m,3); cnt[5]=getx(n,5)-getx(m,5); cnt[7]=f(n,7)-f(m,7); cnt[9]=f(n,9)-f(m,9); //cnt[2]-=cnt[5]; int ans=1; if(cnt[2]>cnt[5]) ans*=mod2[(cnt[2]-cnt[5])%4]; else if(cnt[2]==cnt[5]) ; else ans*=5; ans*=mod3[cnt[3]%4]; //ans*=mod5[cnt[5]%4]; ans*=mod7[cnt[7]%4]; ans*=mod9[cnt[9]%4]; ans%=10; cout<<ans<<endl; } }