ZOJ 3621 Factorial Problem in Base K 分解质因数

来源:互联网 发布:nginx lua waf 安装 编辑:程序博客网 时间:2024/06/03 15:31

题意:坑爹题意不明显。最后才理解是什么意思

给一个k进制的数和进制k,求这个数在十进制下的结果(这个结果在2^63范围内)的阶乘表示为k进制的话末尾有多少个0

比如说样例给的

101 2

表示101是二进制表示形式,把它表示为10进制是5,5!=5*4*3*2*1=120,它的二进制是:1111000,末尾有三个0,所以输出的是3


思路:

我们把这题的问题转换为:

假设s是阶乘的结果

求1~s中包含有多少个k

理由:这个很好想到的。我们可以逆向思考,假设xxx000,x表示未知的,我们可以清晰的看到,这个结果包含3个0,我们可以很容易想到,是有3个10相乘得到的结果。那么我想知道,到底是1~?可以包含3个10呢?然后想一下。10是有2和5组成的对吧?那么我们就可以转换为。1~?中一定要包含3个2,3个或以上的5。

现在我们再转换成正向思考,假设我知道了s,我想知道1~s中到底包含多少个2,多少个5,我取它们之间的最小值就是s!末尾的0的数目了。因为min(2的数目,5的数目)一定是10的个数。


我们总结一下:

我们想知道10进制下s!末尾是0的个数,我们就得知道1~s中包含了多少个10。

那么~我们想知道k进制下s!末尾是0的个数,我们就得知道1~s中包含了多少个k。

这样的话我们就需要对k进行质因数分解了。

另:如果我们知道s,怎么求1~s中包含2的个数?

要理解这句话的意思。假设s是6

1~6中包含多少个2?答案是4个

为什么?2(1)  4(2)  6(1) 不就是4个吗?要知道4是包含有两个2的。

那该怎么求1~s中包含2的个数。

我们另k=s/2,那么k一定是包含2个数,但是这k个数中,可能还有2的倍数,那么再k/2,直到k<2为止

那么我们就有了一个简易的代码:求1~s中包含k的个数

int ret=0;while(s>=k){    ret+=s/k;    s/=k;}
好了,详情看代码:

//author: CHC//First Edit Time:2014-07-17 19:03//Last Edit Time:2014-07-17 19:44#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <set>#include <vector>#include <map>#include <queue>#include <set>#include <algorithm>using namespace std;char str[10000];int k;int getnum(char s){    if(s>='0'&&s<='9')return s-'0';    else if(s>='A'&&s<='Z')return 10+s-'A';    else return 10+26+s-'a';}int zyz[70][100]={0};int zys[70][100]={0};void dosome(int sum){    int &num=zyz[sum][0];    int tmp=sum;    num=0;    for(int i=2;i<=sum;i++){        if(tmp%i==0){            zyz[sum][++num]=i;            int cnt=0;            while(tmp%i==0){                ++cnt;                tmp/=i;            }            zys[sum][i]=cnt;        }    }    return ;}int main(){    for(int i=2;i<70;i++){        dosome(i);    }    while(~scanf("%s%d",str,&k)){        long long s=0;        long long tk=1;        for(int i=strlen(str)-1;i>=0;i--){            s+=tk*getnum(str[i]);            tk*=k;        }        long long n1=-1;        for(int i=1;i<=zyz[k][0];i++){            long long cnt=0;            long long tmp=s;            while(zyz[k][0]<=tmp){                cnt+=tmp/zyz[k][i];                tmp/=zyz[k][i];            }            cnt/=zys[k][zyz[k][i]];            if(n1==-1)n1=cnt;            else if(n1>cnt)n1=cnt;        }        printf("%lld\n",n1);    }    return 0;}



0 0
原创粉丝点击