题意:求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;
}
}