poj1150 求排列Anm的末尾非0数字

题意:求nPm,即n个元素的m中排列方式结果中末尾非0 的数字。


思路: 首先我们知道,2和5相乘末尾非0数字为1,相当于可以相消。我们先把这两个因子抽离出来,考虑末尾为3,7,9的数字。

设f(n,x)为:n!因子中,抽离了2,5,后末尾数字为x的因子个数。分析可以知道f(n,x)=f(n/2,x)+g(n,x); g(n,x)表示n!中所有奇因子末尾数字为x的因子个数。

可以这样分析,对于n!的每一个因子k,如果k是偶数则除二纳入到f(n/2,x)中,如果k是奇数则到g(n,x)中,这样就有了上面那条式子。


接下来分析g(n,x),显然n/10肯定是要的,因为以10为周期,肯定包含3,7,9中的一个,如果n%10>=x,那么加1,还要加上因子中抽离5后的数g(n/5,x)。

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


对于2,5的因子个数可以这样求,getx(n,x),x=2,5,getx(n,x)=getx(n/x,x)+n/x;


现在要算的是n!/m!的结果,因为结果肯定是整数,所以因子个数可以直接相减,

把2,3,5,7,9的数目求出来后,要比较2,5因子个数谁多,2多就要减去5的(相消),相等就两个都不要,5多就要乘以5.

剩下3,7,9因子指数相乘时有个循环节,mod3[4]={1,3,9,7};mod7[4]={1,7,9,3};mod9[4]={1,9,1,9};


看有多少个因子数直接可以得出cnt个x的因子相乘的末尾数。



#include <iostream>
#include <cmath>
#include <stdio.h>
#include <map>
#include <string>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;

#define REP(i,a,b)              for(int i=a;i<b;++i)
#define scan(a)                 scanf("%d",&a)
#define maxn                    500005
#define mset(a,b)               memset(a,b,sizeof a)
#define LL                      long long

int g(int n,int x)
{
    if(!n) return 0;
    return n/10+(n%10>=x)+g(n/5,x);
}

int f(int n,int x)
{
    if(n==0)    return 0;
    return f(n/2,x)+g(n,x);
}

int getx(int n,int x)
{
    if(n<x) return 0;
    return n/x+getx(n/x,x);
}

int mod2[4]={6,2,4,8};
int mod3[4]={1,3,9,7};
int mod7[4]={1,7,9,3};
int mod9[4]={1,9,1,9};

int main()
{
    int n,m;
    int cnt[10];
    while(cin>>n>>m)
    {
        m=n-m;
        cnt[2]=getx(n,2)-getx(m,2);
        cnt[3]=f(n,3)-f(m,3);
        cnt[5]=getx(n,5)-getx(m,5);
        cnt[7]=f(n,7)-f(m,7);
        cnt[9]=f(n,9)-f(m,9);
        //cnt[2]-=cnt[5];
        int ans=1;
        if(cnt[2]>cnt[5])
            ans*=mod2[(cnt[2]-cnt[5])%4];
        else if(cnt[2]==cnt[5]) ;
        else ans*=5;
        ans*=mod3[cnt[3]%4];
        //ans*=mod5[cnt[5]%4];
        ans*=mod7[cnt[7]%4];
        ans*=mod9[cnt[9]%4];
        ans%=10;
        cout<<ans<<endl;
    }
}


你可能感兴趣的:(poj1150 求排列Anm的末尾非0数字)