Codeforces 1114C Trailing Loves (or L'oeufs?)

题目链接:http://codeforces.com/problemset/problem/1114/C
算是一个比较经典的数论题目,有一定的数论基础的话是不难想出来这个题目的做法的

题意:

求n的阶乘在b进制下末尾有多少个零

题解:

要完成这个题目,需要用到数论里的唯一分解定理;
唯一分解定理说的是任何一个大于一的正整数,都可以被分解为若干素数的乘积,而且形式唯一。
对于这个题目,我们通过进制的知识可以知道,在b进制下后边有几个零,代表这个数字是b的几次方的倍数
比如:100010(2) = 34(10) = 2 × 17是二的一次方的倍数
1100(2) = 12(10) = 4 × 3是二的二次方的倍数
于是题目便转化为了求n的阶乘最大能够被b的多少次方整除
由唯一分解定理我们可以知道,我们对于n的阶乘做唯一分解,同时对b做唯一分解,得到
b = p1 a1 · p2 a2 · p3 a3
n! = p1 b1 · p2 b2 · p3 b3
那么n的阶乘最大能够被b的多少次方整除就转换为了求min{b1 / a1,b2 / a2…}
我们考虑到n的阶乘的特殊性,即它是1 ~ n连续数字的乘积,而在1 ~ n中p1、p2…他们的倍数是周期性变换的,
比如6!在二进制下,1~6中2的倍数出现了3次,4的倍数出现了1次,我们对6的阶乘进行唯一分解
6! = 720 = 2 4 × 3 2 × 5 1 于是后边的零为4个
从而我们得知,对于n的阶乘,它的唯一分解中p的次数等于1~n中p的各个次方(从一次方开始)出现的次数之和
即sum{n / p1,n / p2,n / p3,…}
这样我们就可以求出n的阶乘最大能够被b的多少次方整除

PS:关于唯一分解的方法,参照求欧拉函数的方法,复杂度为log2n;注意不要爆longlong

代码

#include <cstring>
#include <bits/stdc++.h>
#define ll long long
#define MAXN 200003
using namespace std;

ll res[MAXN],num[MAXN];
int main()
{
    ll n,b;
    int k = 0;
    scanf("%I64d%I64d",&n,&b);
    for(ll i = 2;i <= sqrt(b);i++)
    {
        if(b % i == 0)
        {
            ll t = 0;
            while(b % i == 0)
            {
                b /= i;
                t++;
            }
            res[++k] = i;
            num[k] = t;
        }
    }
    if(b != 1)
    {
        res[++k] = b;
        num[k] = 1;
    }
    ll ans = -1;
    for(int i = 1;i <= k;i++)
    {
        ll T = 0;
        ll t = 1;
        while(t <= n / res[i])
        {
            t *= res[i];
            T++;
        }
        //printf("%d\n",t);
        ll temp = 0,sum = 0,cnt = 0;
        for(ll j = T;j >= 1LL;j--)
        {
            temp = n / t - cnt;
            cnt = n / t;
            sum += temp * j;
            //printf("T%I64d %I64d %I64d\n",temp,j,sum);
            t /= res[i];
        }

        if(ans != -1)
            ans = min(ans,sum / num[i]);
        else
            ans = sum / num[i];
    }
    printf("%I64d\n",ans);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值