T组数据,给出N,求出N!最右边非零的数。
对于30%的数据,N <= 30,T<=10。
对于全部的数据,N <= 10^2009,T<=30。
一道数学题
解析
N!/(10^x)最后一位数字即是结果。10^x进行拆分,变成5^x* 2^x。怎么除以5^x呢,好办,乘的时候含有5的倍数的一项全部不乘进去,再递归此过程。即
1 2 3 4 (15) 6 7 8 9 (25)
11 12 13 14 (35)16 17 18 19 (45)
21 22 23 24 (55) 26 27 28 29 (65) ...
再递归处理
1 2 3 4 (1*5) 6
而且可以发现,不算5倍数一项进去,每十个一组,最末尾结果是一样的:6,且6*6还是6!
接下来的问题,怎么除2^x呢?
分析发现:
2^0 = 1
2^1 = 2
2^2 = 4
2^3 = 8
2^4 =16=(6)
且2,4,6,8乘以6最末尾还是原来的数。所以,可以分析看x%4是多少,若为1,说明原来的结果相当于多乘了一个2(其他的那些2刚好是4的倍数,不影响结果),所以,我们本来是要除以2的,但是很显然对结果再补乘3个2(2^3)即可消除影响,得到正确答案。其他情况同理。至此,思路理顺。
代码
#include<bits/stdc++.h>
using namespace std;
int T,n,ans,mod,rest,x;
bool flag;
const int v[10]={1,1,2,6,4,4,4,8,4,6};
char s[3000];
int a[3000];
const int k[4]={6,8,4,2};
int main(){
scanf("%d",&T);
while(T--){
scanf("%s",s);
memset(a,0,sizeof(a));
n=strlen(s);
for(int i=1;i<=n;++i){
a[i]=s[n-i]-'0';
}
ans=1;
mod=0;
flag=0;
while(1){
rest=0;
ans=(ans*v[a[1]])%10;
if(n>1) ans=(ans*6)%10;
for(int i=n;i>=1;i--){
x=rest*10+a[i];
rest=x%5;a[i]=x/5;
}
while((n>0)&&(a[n]==0)) n--;
if(n==0) break;
flag=true;
mod=(mod+a[2]*10+a[1])%4;
}
if(flag) ans=(ans*k[mod])%10;
printf("%d\n",ans);
}
return 0;
}