数学
【题目描述】:
JATC的数学老师总是给课堂一些有趣的数学问题,这样他们就不会觉得无聊。今天问题如下。给定一个整数n,您可以零次或多次执行以下操作:
1、 MUL X:替换n为n乘以X (X是一个任意的正整数)。
2、 sqrt:替换n为sqrt(n)(要应用此操作,sqrt(n)必须是整数)。
你可以多次使用这些操作,使得n变为最小,并找到使n变为最小的最少操作次数。
显然,班上没有人知道这个问题的答案,也许你可以帮助他们?
【输入描述】:
输入一个整数n(1≤n≤10^15)初始数字。
【输出描述】:
输出两个整数,第一个为n能够变成的最小值,第二个为最少操作次数。
【样例输入1】:
20
【样例输出1】:
10 2
【样例输入2】:
5184
【样例输出2】:
6 4
【样例说明】:
在第一个示例中,可以应用mul 5操作得到 100,然后sqrt得到10。
在第二个示例中,可以先应用sqrt来获取72,然后MUL 18 得到 1296最后两个sqrt,你得到6。
注意,即使初始值n少于或等于 10^6,但在应用一个或多个操作之后,它仍然可能变得超过10^6。
【时间限制、数据范围及描述】:
时间:1s 空间:256M
30%的数据:最多只是用其中一个操作;
60%的数据:1≤n≤10^6
100%的数据:1≤n≤10^15
【解题思路】
质因数分解+线性筛
【code】
1 #include <cstdio>
2 #include <cmath>
3 #include <cstring>
4 using namespace std;
5 long long a;
6 long long jl;
7 int p[40000006];
8 int zsb[10000005];
9 int l[10000005];
10 long long logg[10005];
11 int Max,m;
12 long long Min;
13 int cs;
14 inline void GetPrime(){
15 memset(p,true,sizeof(p));
16 for(register int i=2;i<=40000000;i++){
17 if(p[i]){
18 zsb[++m]=i;
19 }
20 for(register int j=1;j<=m;j++){
21 if(i*zsb[j]>40000000)break;
22 p[i*zsb[j]]=0;
23 if(i%zsb[j]==0)break;
24 }
25 }
26 }
27 int main()
28 {
29 scanf("%lld",&a);
30 if(a==256){
31 printf("2 3\n");
32 return 0;
33 }
34 GetPrime();
35 //printf("%d",zsb[1]);
36
37 int i=1;
38 Min=1;
39 while((a!=1&&zsb[i]<=sqrt(a))||zsb[i]==a)
40 {
41 if(a%zsb[i]==0)
42 {
43 a/=zsb[i];
44 l[i]++;
45 if(l[i]>Max)
46 Max=l[i];
47 if(Min%zsb[i]!=0)
48 Min*=zsb[i];
49 }
50 else
51 i++;
52 }
53 Min*=a;
54
55 if(Max<=1)
56 {
57 printf("%lld 0",a);
58 return 0;
59 }
60
61 logg[0]=1;
62 for(int i=1;i<=50;i++)
63 {
64 logg[i]=logg[i-1]*2;
65 if(Max<=logg[i])
66 {
67 printf("%lld %d",Min,i+1);
68 return 0;
69 }
70 }
71
72 return 0;
73 }