排列Anm的末尾非0数字(poj1150)

题目连接
题意:求 Pmn n!m! 中末尾非0 的数字。

思路: 首先我们知道,2和5相乘末尾非0数字为1,可以相互相消。我们先把这两个因子抽离出来,考虑末尾为3,7,9的因子。
定义 f(n,x):n! 因子中,抽离了2,5后末尾数字为 x 的因子的个数。
g(n,x):n!中所有奇因子末尾数字为 x 的因子的个数。
分析可以知道f(n,x)=f(n2,x)+g(n,x);
可以这样想,对于 n!kkf(n2,x)kg(n,x) 中,这样就有了上面那条式子。

g(n,x),13579,15g(n5,x)x=357, n10xn%10x,1,5g(n5,x)
g(n,x)=n10+(n%10x)+g(n5,x) ;

2,5getx(n,x)=getx(nx,x)+nx(x=2,5);

现在要算的是 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};

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

#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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值