洛谷 P3927 SAC E#1 - 一道中档题 Factorial

洛谷 P3927 SAC E#1 - 一道中档题 Factorial


题目

题目背景

数据已修改

SOL君(炉石主播)和SOL菌(完美信息教室讲师)是好朋友。

题目描述

SOL君很喜欢阶乘。而SOL菌很喜欢研究进制。

这一天,SOL君跟SOL菌炫技,随口算出了n的阶乘。

SOL菌表示不服,立刻就要算这个数在k进制表示下末尾0的个数。

但是SOL菌太菜了于是请你帮忙。

输入输出格式

输入格式:
每组输入仅包含一行:两个整数n,k。

输出格式:
输出一个整数:n!在k进制下后缀0的个数。

输入输出样例

输入样例#1:

10 40

输出样例#1:

2

说明

对于20%的数据,n <= 1000000, k = 10

对于另外20%的数据,n <= 20, k <= 36

对于100%的数据,n <= 10^12,k <= 10^12且k≠1


题解

首先,我们可以知道,一个数改成k进制后,他末尾为0的个数为该数能整除k的次数

然后,我们就可以想到,把k分成质因子以及其出现个数

对于每一个质因子,我们从x的阶乘中找出1~x中可以分解出多少个质因子,然后将得到的答案/改质因子出现的次数,取min值,最后即为答案

对于从1~x中找出能分解出质数y的个数可以用不断重复x/=y直至x==0,x分别表示从1~x中y^1,y^2,y^3……的倍数出现的个数

然而,知道了这些的我依然不会做,╮(╯▽╰)╭,所以,求大佬帮我看一下哪个地方弄错了


代码(未AC)

#include
#include
#define ll long long
using namespace std;

ll n,m,tot,up,cnt,now,w,ans;
ll prime[500005],q[100005],t[100005];
bool vis[1000005];

ll min(ll x,ll y)
{
    if (x<y) return x; else return y;
}

int main()
{
    scanf("%lld%lld",&n,&m);
    up=trunc(sqrt(m));tot=0;cnt=0;
    for (ll i=2;i<=up+4;i++)
    {
        if (!vis[i]) prime[++tot]=i;
        for (ll j=1;j<=tot&&prime[j]*i<=up+4;j++)
        {
            vis[i*prime[j]]=1;
            if (i%prime[j]==0) break;
        }
    }
    for (ll i=1;prime[i]<=up+4&&m!=1;i++)
    {
        if (m%prime[i]==0)
        {
            q[++cnt]=prime[i];
            while (m%prime[i]==0) t[cnt]++,m/=prime[i];
        }
    }
    ans=1e18;
    if (m>1) prime[++cnt]=m,t[cnt]++;
    for (ll i=1;i<=cnt;i++)
    {
        now=0;w=n;
        while (w!=0) now+=w/q[i],w/=q[i];
        ans=min(now/t[i],ans);
    }
    printf("%lld\n",ans);
    return 0;
}

你可能感兴趣的:(洛谷,数学)