时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
令 X = n!, 给定一大于1的正整数p 求一个k使得 p ^k | X 并且 p ^(k + 1) 不是X的因子。
输入描述:
两个数n, p (1e18>= n>= 10000 >= p >= 2)
输出描述:
一个数 表示k
示例1
输入
复制
10000 12
输出
复制
4996
题意:
找出一个k,使得X%p^k==0 && X%p^(k+1)!=0。
思路:
我们可以对一个数进行分解。一个数如果所有质因子的对应个数都小于等于另一个数的对应的个数,那么这个数是另一个数的因子。否则不是。阶乘的分解也很好推。
本题n的范围是1e18,而p的范围是10000,那么我们就只需要考虑10000范围内的质因子就行了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 10005
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3f
#define mod 1000000007
ll n,p;
ll dp[MAXN],dis[MAXN];
int prime[MAXN];
bool is_prime[MAXN];
int sieve(int nn)
{
int pn = 0;
memset(is_prime,true,sizeof(is_prime));
is_prime[0] = is_prime[1] = false;
for(int i = 2; i <= nn; i++)
{
if(is_prime[i])
prime[pn++] = i;
for(int j=0; j<pn && prime[j]*i<=nn; j++)
{
is_prime[prime[j]*i]=false;
if(i%prime[j]==0) //¹Ø¼üµã
break;
}
}
return pn;
}
int main()
{
scanf("%lld%lld",&n,&p);
int cnt=sieve(10000);
memset(dp,0,sizeof dp);
for(int i=0;i<cnt && prime[i]<=n;i++)
{
ll num=prime[i];
for(ll j=num;j<=n;j*=num)
{
if(j<0) break;
dp[num]+=n/j;
}
}
memset(dis,0,sizeof dis);
ll minn=inf;
for(int i=0;i<cnt && prime[i]<=p;i++)
{
ll num=prime[i];
while(p && p%num==0)
{
dis[num]++;
p/=num;
}
if(dis[num]==0) continue;
minn=min(minn,dp[num]/dis[num]);
}
printf("%lld\n",minn);
return 0;
}