现在的位置: 首页 > 综合 > 正文

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

2018年01月11日 ⁄ 综合 ⁄ 共 1745字 ⁄ 字号 评论关闭

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

给一个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;
}

抱歉!评论已关闭.