/*
求N!最后非0位的值。比如2是120的最后一个不是0的值。
输入N比较大,要大数保存。
注意到最后0的个数是与5的因数的个数相等。设f(n)为n!的最后非0位。
那么f(n)=((n%5)!* f(n/5) *2^(n/5))%10
因数2的个数始终大于5,从1开始每连续5个划分为1组,其中5的倍数只提取出一个因数5后,
组成一个新的数列1到n/5,我们有1*2*3*4*5=6*7*8*9*5=11*12*13*14*5=...=2(取最后一个非0位),这里就是2^(n/5)。
再乘上剩下来的几个数字即可
(比如n是123,那么第一次会剩下121,122,123三个数没有被分配)。
参考: http://hi.baidu.com/nicker2010/item/4fa83c4c5050b3e5a4c066ec 代码三
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int Lib[4]={6,2,4,8}; //2^n的尾数为2,4,8,6的循环
const int fact[10]={1,1,2,6,4,2,2,4,2,8}; //10以内的阶乘尾数
char s[200];
int a[200]; //存大数,a[0]存数的位数
void todigit(char s[],int a[])
{
a[2]=0;
a[0]=strlen(s);
for (int i=0; i<a[0]; i++) a[a[0]-i]=s[i]-'0';
}
void mult(int a[],int x) //高精度除法
{
int j=0;
for (int i=a[0]; i>0; i--)
{
int k1=(j*10+a[i])/x;
j=(j*10+a[i])%x;
a[i]=k1;
}
while (a[0]>1 && a[a[0]]==0) a[0]--;
}
int last_nunzero(int a[])
{
if (a[0]==1) return fact[a[1]];
int x1=fact[a[1]%5]; //x1=(n%5)!
mult(a,5);
int x2=Lib[(a[2]*10+a[1])%4]; //x2=(2^(n/5))%10
int ret=(x1*x2*last_nunzero(a))%10; //递推公式的还原
return ret;
}
int main()
{
while (gets(s))
{
todigit(s,a);
printf("%d\n",last_nunzero(a));
}
return 0;
}
/*
网路上的另一个更高效的模板: (思路不甚理解,同参考网址的代码四(代码四本身是WA的~),)
#include <stdio.h>
#include <string.h>
#define MAXN 10000
int lastdigit(char* buf){
const int mod[20]={1,1,2,6,4,2,2,4,2,8,4,4,8,4,6,8,8,6,8,2};
int len=strlen(buf),a[MAXN],i,c,ret=1;
if (len==1)
return mod[buf[0]-'0'];
for (i=0;i<len;i++)
a[i]=buf[len-1-i]-'0';
for (;len;len-=!a[len-1]){
ret=ret*mod[a[1]%2*10+a[0]]%5;
for (c=0,i=len-1;i>=0;i--)
c=c*10+a[i],a[i]=c/5,c%=5;
}
return ret+ret%2*5;
}
int main()
{
char en[1000];
while(scanf("%s",en)!=EOF)
{
int temp = lastdigit(en);
printf("%d\n",temp);
}
return 0;
}
*/
HDOJ1066-数学,N!的非零尾数
最新推荐文章于 2019-03-10 14:19:42 发布