Codeforces #538 (Div. 2) C. Trailing Loves (唯一分解定理)

题目:https://codeforces.com/problemset/problem/1114/C

题目大意: 求n!能被b整除几次

看到n的范围为1e18,b的范围为1e12,下意识就觉得该在b身上动手脚,开根号后刚好1e6,跟开根号相关的算法就会一个唯一分解…
分解后b可以表示为x1*p1+x2*p2....+xn*pn我们只需要求n!里有多少p1,p2…pn的个数 类似得到y1*p1+y2*p2....+yn*pn
最后答案就是min(y1/x1,y2/x2,......,yn/xn)
如何得到y呢,举个例子 当n=123,b=11 ⌊ 123 11 ⌋ \left\lfloor\frac{123}{11}\right\rfloor 11123是1-123中11的倍数的个数,这些数中都至少有一个11,我们另这个数为T1,那么这些11的倍数至少为y共享T1个11,所以y+=T1.再考虑贡献为2的情况,则 ⌊ x 1 11 ⌋ \left\lfloor\frac{x1}{11}\right\rfloor 11x1是11*11的倍数的个数T2,因为他们已经在T1中算过贡献一次,则y+=T2 .重复这个过程直到Tn为0 我们就能求出123!中11对应的y为多少

#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<stdlib.h>
#include<algorithm>
#include<time.h>
#include<unordered_map>
#define bug1(g) cout<<"test: "<<g<<endl
#define bug2(g,i) cout<<"test: "<<g<<" "<<i<<endl
#define bug3(g,i,k) cout<<"test: "<<g<<" "<<i<<" "<<k<<endl
using namespace std;
typedef unsigned long long ll;
ll n,b;

ll sol()
{
    ll ans=0,t=2e18;
    for(ll i =2;i*i<=b;i++)
    {
        if(b%i==0)
        {
            ll k =0,ha=i; //k代表b中有多少i
            while(b%i==0){b/=i;++k;ha*=i;}
            //bug3(b,k,ha);
            //if(n/i>=k&&k)
            ll x=n/i,tt=x; //x代表n!有多少i
            while(tt/i)
                {
                    x+=tt/i;
                    tt/=i;
                }
            t=min(t,x/k);
            //else t=0;
        }
        if(b==1) break;
    }
    if(b!=1) //b为质数
    {
         ll x=n/b,tt=x;
        while(tt/b)
            {
                x+=tt/b;
                tt/=b;
            }
        t=min(t,x);
    }
    return t;
}
int main()
{
    ios::sync_with_stdio(0);
    cin>>n>>b;
    cout<<sol()<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值