hdu 1066 分类: hdu 2015-03-16 21:40 36人阅读 评论(0) 收藏

给出正整数N,请求出N!最右非零的数位的值。


ans(N!)=ans(1234...N)=f(N)g(N)mod10

f(i)=(1234)(6789)(11121314)...(...i)mod10
f(i)=(1234)(6789)(1234)...(...(imod10))mod10

g(i)=51015202530...(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的幂的个位数具有明显周期性,Tg=4 ,只与 [i/5] 的最后两位数字有关。

最后,gcd(TfTg)=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  
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

posted @ 2015-03-16 21:40  <Dash>  阅读(167)  评论(0编辑  收藏  举报