题目: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;
}