yzoj 1122 阶乘 题解

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;
}
上一篇:YZOJ一道简单题杂谈


下一篇:LeetCode 162. Find Peak Element