数论
题目描述
给定正整数 n,k,已知非负整数 x满足 n! mod k^x=0,求最大的x为多少? 输入格式本题包含多组数据,请处理至文件末尾。对于每组数据,共有一行,两个整数,表示 n,k。 输出格式对于每组数据,输出一行,一个整数,表示 最大的x。
输入样例
10 2
5000000000000000000 2
5000000000000000000 10000000000000
输出样例
8
4999999999999999981
96153846153846153
数据范围与提示
对于 40%的数据,k<=2×10^7,n<=2×10^9,数据组数<=50。
对于 100%的数据,1<k<=10^13,1<=n<=5×10^18,数据组数 <=200。
数论基本操作:唯一分解定理。
• 第一点,像这种只给两个数的数论题,我们先寻找切入点,k 比较小。
• 第二点,思路就是看答案“长什么样”。
• 显然答案可以写成 n!= p *(k ^ x) ,需要最大化 x 。
• 那么 x 是受到什么的限制呢?
• 分解他们会发现显然的一个条件:对于每一的质数q,我们假设 n!最多能够分解出 a 个 q ,
而 k 能够分解出 b 个 q 。显然 a >= b * x 。
• 接下来就明确目的了,我们可以在 √k 的时间内分解 k (不过多组数据建议预处理素数)
• 然后需要知道 n!能分解出多少个对应的素数,那我们反着考虑每个素数 ,就可以在很快
的时间内算出答案了。
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 int top; 5 ll n,k,m,tmp,ans,tot,t[100],sum[100]; 6 ll p[2000050],cnt; 7 bool vis[4000050]; 8 void calc() 9 { 10 for(int i=2;i<=4000000;++i) 11 { 12 if(!vis[i]) 13 p[++cnt]=i; 14 for(int j=1;j<=cnt;++j) 15 { 16 tmp=(ll)p[j]*i; 17 if(tmp>4000000) 18 break; 19 vis[tmp]=true; 20 if(i%p[j]==0) 21 break; 22 } 23 } 24 } 25 int main() 26 { 27 calc(); 28 while(scanf("%lld%lld",&n,&k)!=EOF) 29 { 30 m=sqrt(k);top=0; 31 ans=6999999999999999999; 32 for(int i=1;p[i]<=m;++i) 33 if(k%p[i]==0) 34 { 35 ++top; 36 t[top]=p[i],sum[top]=0; 37 while(k%p[i]==0) 38 { 39 k/=p[i]; 40 ++sum[top]; 41 } 42 } 43 if(k>1) 44 { 45 t[++top]=k; 46 sum[top]=1; 47 } 48 for(int i=1;i<=top;++i) 49 { 50 tot=0;tmp=t[i]; 51 for(;tmp<=n;tmp*=t[i]) 52 { 53 if(tmp<=0||tmp%t[i]) 54 break; 55 tot+=n/tmp; 56 } 57 ans=min(ans,tot/sum[i]); 58 } 59 printf("%lld\n",ans); 60 } 61 return 0; 62 }