给出正整数N,请求出N!最右非零的数位的值。
ans(N!)=ans(1∗2∗3∗4∗...∗N)=f(N)∗g(N)mod10
f(i)=(1∗2∗3∗4)∗(6∗7∗8∗9)∗(11∗12∗13∗14)∗...∗(...∗i)mod10
f(i)=(1∗2∗3∗4)∗(6∗7∗8∗9)∗(1∗2∗3∗4)∗...∗(...∗(imod10))mod10
g(i)=5∗10∗15∗20∗25∗30∗...∗(i−(imod5))
g(i)=f([i/5])∗5[i/5]=f([i/5])∗5[i/5]∗10−[i/5]=f([i/5])∗2−[i/5] (2的因子个数远远多于5的因子个数)
f(i)
的实现:当
i>=10
时,
f(i)
具有明显周期性,
Tf=10
,只与个位数字有关。
g(i)
的实现:
2
的幂的个位数具有明显周期性,
最后, gcd(Tf,Tg)=20 ,嗯,于是,大家都懂了。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
const int MAXN = 1000;
int list[25] = {1,1,2,6,4,2,2,4,2,8,4,4,8,4,6,8,8,6,8,2};
struct bignumber
{
int l , n[MAXN];
void ten()
{
for(int i = 1; i < l ;i++)n[i] = n[i+1]; n[l--] = 0;
}
void two()
{
for(int i = 1 ; i <= l ; i++)n[i] <<= 1;
for(int i = 1 ; i <= l ; i++){n[i+1]+=n[i]/10,n[i]%=10;}
l += (n[l+1])?1:0;
}
}num;
char ch[MAXN] = {'\0'};
int slove()
{
int ans = 1;
while (num.l)
{
ans = ans * list[(num.n[2]&1)*10+num.n[1]] % 10;
num.two(); num.ten();
}
return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("hdu1066.in","r",stdin);
freopen("hdu1066.out","w",stdout);
#endif
while(scanf("%s",ch)!=EOF)
{
memset(num.n,0,sizeof(num.n));num.l = 0;
int len = strlen(ch);
for(int i = len-1 ,j = 1 ; i >= 0 ; i--,j++)
num.n[j] = ch[i] - '0';
for(int i = len ; i >=1 ; i--)
if(num.n[i]){num.l = i;break;}
printf("%d\n",slove());
}
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
}