题目总结:哇,还真是质因子筛选!考试的时候想到了质因子个数相除,但不知道一个阶乘该如何计算出一个因子的个数......
求一个大数n的阶乘的所含因子p的个数,我们知道,
n!=1*2*3*4*......n
为求出p的个数,将上式表示为
n!=(p*2p*3p*4p*......*kp)*q,其中q就是其他不是因子p的倍数的乘积,比如10!=(2*(2*2)*(3*2)*......(5*2))*q,q是不含p的可以不管,k=n/p;
这样,我们可以提出k个p出来,原式为
n!=p^k*k!*q,再将k!像上面的方法一样分解,就可以得到p的个数
代码如下:
//阶乘因子分解,找出n!中有多少个p
ll findnum(ll n,ll p)
{
ll ans=0;//个数
if(k==0)return 0;
while(n)
{
ans+=n/p;//一次变换后的个数
n/=p;//将k=n/p再迭代
}
return ans;
}
那么,我们就可以将给定的p进行质因子分解,找出质因子和它们的个数,再用上述方法找到n!中p的每个质因子的个数,找到两者相除的最小值就是答案。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
typedef long long ll;
/*
筛出p的最小质数和个数,再用快速算法求出n!中含有多少个最小质数
两者个数相处就得到答案k
快速求N!中有多少质数m的算法就是迭代公式
*/
const ll maxn=10001;
int isprime[maxn];
int notprime[maxn];
ll n_num[maxn];//n的每个质因子个数
ll p_num[maxn];//p的每个质因子个数
int cnt;
//筛选质数
void eular()
{
memset(isprime,0,sizeof(isprime));
memset(notprime,0,sizeof(notprime));
cnt=0;
for(int i=2;i<maxn;i++)
{
if(!notprime[i])
{
isprime[++cnt]=i;
}
for(int j=1;j<=cnt&&i*isprime[j]<maxn;j++)
{
notprime[i*isprime[j]]=1;
if(i%isprime[j]==0)
break;
}
}
}
//阶乘因子分解,找出n!中有多少个p
ll findnum(ll n,ll p)
{
ll ans=0;
while(n)
{
ans+=n/p;
n/=p;
}
return ans;
}
int main()
{
ll n,p;
eular();
int tot=1;
while(scanf("%lld%lld",&n,&p)!=EOF)
{
memset(n_num,0,sizeof(n_num));
memset(p_num,0,sizeof(p_num));
while(p!=1)
{
//求p的每个质因子的个数
while(p%isprime[tot]==0&&p)
{
p_num[tot]++;
p/=isprime[tot];
}
tot++;
}
for(int i=1;i<=tot;i++)
{
n_num[i]=findnum(n,isprime[i]);
}
ll ans=2e18+5;
for(int i=1;i<=cnt;i++)
{
if(p_num[i])
ans=min(ans,n_num[i]/p_num[i]);//找一个最小的因子数之商
}
printf("%lld\n",ans);
}
return 0;
}