思路
数据太大不可能直接计算,首先想到的思路应该是将n!和a分解成质因子的幂指数形式。a的分解很简单,关键是在于n!的分解。
考虑某个质因子p,则在1到n中一定有n/p个数,每个数至少向p的幂次贡献了1。(因为至少有n/p个p的倍数属于1到n,而在计算阶乘的时候这些倍数都会算上)。如果n/p为0,那么不可能还会有p的倍数向n!的分解贡献幂次,想一想为什么?
然后计算p*p,则和上面描述的一样,共有n/(p*p)个数对p的幂次贡献了1。为什么不是2呢?这是因为在计算n/p的时候已经计算过一遍了,所以不需要重复计算。
依次迭代,直到n/(p^k)为0,关于p的幂次才算计算完成。
那么如何计算k呢,现在已经得到a和n!的分解了,如果n!可以整除a^k,那么a的所有质因子都可以在n!中找到,并且k为相应幂次的倍数。
n!=p1e1 *p2e2 ··· piei ···
a==p1ee1 *p2ee2 ··· pieei ···
则e1>=k*ee1 ,e2>=k*ee2 ……
找出其中最小的倍数k即可。
#include <iostream>
#include <queue>
#include <stdlib.h>
#include <stdio.h>
#include <map>
#include <string>
#include <cstdlib>
#include <stack>
#include <vector>
#include <math.h>
#include <algorithm>
#include <typeinfo>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn = 1000004;
int prime[maxn];
std::vector<int> prm;
int fpow(int base,int exp){
int ans=1;
while(exp){
if(exp&1) ans*=base;
base*=base;
exp>>=1;
}
return ans;
}
void cr(void){
memset(prime,1,sizeof(prime));
prime[0]=prime[1]=0;
for(int i=2;i<maxn;i++){
if(prime[i]){
prm.push_back(i);
for(int j=i*2;j<maxn;j+=i)
prime[j]=0;
}
}
return;
}
int a[1003],b[1003];
int main(int argc, char const *argv[])
{
cr();
ll n,aa;
while(cin>>n>>aa){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
int cnt;
for(int i=2;i<=n;i++){
cnt=0;
if(prime[i]){
int p=1;
while(n/fpow(i,p)){
cnt+=n/fpow(i,p);
p++;
}
a[i]=cnt;
}
}
int s=aa;
for(int i=2;i<=s;i++){
if(prime[i]){
int cnt=0;
while(aa%i==0){
cnt++;
aa/=i;
}
b[i]=cnt;
}
}
/*for(int i=2;i<=s;i++)
cout<<b[i]<<" ";
cout<<endl;*/
int mi=0x3f3f3f3f;
for(int i=2;i<n;i++){
if(b[i]){
if(mi>a[i]/b[i])
mi=a[i]/b[i];
}
}
cout<<mi<<endl;
}
return 0;
}