数论---------------基本数论

数论

题目描述

给定正整数 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 }
代码

猜你喜欢

转载自www.cnblogs.com/wyher/p/9815758.html