求n!,C(n,m)和A(n,m)最后的非零位。

n!C(n,m)A(n,m)最后的非零位。

 

先说说怎样求n!最后的非零位吧!

比如找10!最后的非零位,由于质因数25的组合之后末尾会产生0,所以我们先把25的质因子全部去掉,由于2的数目要比5多,所以我们要在最后考虑

多余的2对末尾的影响。

比如:1*2*3*4*5*6*7*8*9*10去掉25的因子后就是:

1*1*3*1*1*3*7*1*9*1,由于去掉了25,那么剩下的数字末尾一定是3791四者之一,然后我们再求出这么一串数相乘以后末尾的数是几,最后再补上

2对末位的影响即可。

所以,求n!最后非零位分为4步:

(1)将n!中所有的25因子去掉

(2)求出剩下的一串数字相乘后末尾的那个数

(3)由于25多,考虑多余的2对结果的影响

(4)输出答案

对于步骤(1),直接计算去除就行了,很简单。

对于步骤(2),是难点,这个问题可以转化为求出这些数里面末尾是379的数字出现的次数,因为这些数的n次方是有规律的,周期为4.

现在的问题就是如何求出这串数字末尾379各自出现的次数了。

一个数列实际上可以分为偶数列和奇数列。

例如:1*2*3*4*5*6*7*8*9*10

分成:13579246810两部分

这样我们尝试分别进行统计,可以发现,实际上246810中的个数也就是12345中的个数,也就是说我们又把这个问题划分成了一个原来问

题的子问题。

f(n)=f(n/2)+g(n)g(n)表示奇数列中的数目,我们需要解决g(n),再次观察g(n),实际上又分成了两部分:13791113171921....................

以及5的奇倍数51525........

说明又出现了子问题。

如果要统计这个数列中末尾为x(x1379)的个数可以这样写:

g(n,x)=n/10+(n%10>=x)+g(n/5,x)

这样利用了两个递归方程,我们可以在logn的时间内计算出末尾为1379的数的个数了

在得到这串数字中末尾是379的数字个数后,再利用循环节的性质可以快速求出这串数字相乘后mod10的结果,再考虑当时多余的2,便可以求出答案。

知道了这个之后,求A(n,m)就不难了。

先求出n!和(n-m)!25379分别出现的次数,然后各自相减,再用循环节处理即可。

这里还要注意一下:2的出现次数如果小于5的出现次数,我们可以直接输出5,如果2的出现次数等于5的出现次数,那么2的循环节不需要考虑。至于3

79的循环节,由于这些数的4次方末尾刚好为1,所以不需要特殊考虑

 

题目:求A(n,m)最后的非零位数字。题目链接:POJ1150

#include <iostream>

using namespace std;

int GetCount(int n,int x)    /**计算n!中质因子x出现的次数*/
{
    if(n==0) return 0;
    return n/x+GetCount(n/x,x);
}

int g(int n,int x)           /**计算f(1)到f(n)中奇数数列中末尾为x的数出现的次数*/
{
    if(n==0) return 0;
    return n/10+(n%10>=x)+g(n/5,x);
}

int getx(int n,int x)        /**计算f(1)到f(n)中,末尾为x的数的出现次数*/
{
    if(n==0) return 0;
    return getx(n/2,x)+g(n,x);
}

int table[4][4]=
{
     6,2,4,8,
     1,3,9,7,
     1,7,9,3,
     1,9,1,9
};

int main()
{
    int n,m;
    int num2,num3,num5,num7,num9;
    while(cin>>n>>m)
    {
        num2=GetCount(n,2)-GetCount(n-m,2);
        num5=GetCount(n,5)-GetCount(n-m,5);
        num3=getx(n,3)-getx(n-m,3);
        num7=getx(n,7)-getx(n-m,7);
        num9=getx(n,9)-getx(n-m,9);
        int ans=1;
        if(num5>num2)
        {
            cout<<"5"<<endl;
            continue;
        }
        if(num2!=num5)
        {
            ans*=table[0][(num2-num5)%4];
            ans%=10;
        }
        ans*=table[1][num3%4];
        ans%=10;
        ans*=table[2][num7%4];
        ans%=10;
        ans*=table[3][num9%4];
        ans%=10;
        cout<<ans<<endl;
    }
    return 0;
}

题目:求C(n,m)最后的非零位数字。题目链接:POJ3406

由于m的阶乘和n-m的阶乘的乘积并不是n的阶乘的子集,所以这题要多加一个循环模

#include <iostream>

using namespace std;

int GetCount(int n,int x)    /**计算n!中质因子x出现的次数*/
{
    if(n==0) return 0;
    return n/x+GetCount(n/x,x);
}

int g(int n,int x)           /**计算f(1)到f(n)中奇数数列中末尾为x的数出现的次数*/
{
    if(n==0) return 0;
    return n/10+(n%10>=x)+g(n/5,x);
}

int getx(int n,int x)        /**计算f(1)到f(n)中,末尾为x的数的出现次数*/
{
    if(n==0) return 0;
    return getx(n/2,x)+g(n,x);
}

int table[4][4]=
{
     6,2,4,8,
     1,3,9,7,
     1,7,9,3,
     1,9,1,9
};

int main()
{
    int n,m;
    int num2,num3,num5,num7,num9;
    while(cin>>n>>m)
    {
        num2=GetCount(n,2)-GetCount(n-m,2)-GetCount(m,2);
        num5=GetCount(n,5)-GetCount(n-m,5)-GetCount(m,5);
        num3=getx(n,3)-getx(n-m,3)-getx(m,3);
        num7=getx(n,7)-getx(n-m,7)-getx(m,7);
        num9=getx(n,9)-getx(n-m,9)-getx(m,9);
        int ans=1;
        if(num5>num2)
        {
            cout<<"5"<<endl;
            continue;
        }
        if(num2!=num5)
        {
            ans*=table[0][(num2-num5)%4];
            ans%=10;
        }
        ans*=table[1][(num3%4+4)%4];
        ans%=10;
        ans*=table[2][(num7%4+4)%4];
        ans%=10;
        ans*=table[3][(num9%4+4)%4];
        ans%=10;
        cout<<ans<<endl;
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值