UOJ #548. 数学

【题目描述】:

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

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
 
const int N=10000000;
 
bool u[N+10];
int su[5000000], num;
 
void prepare() {
    int i,j;
    memset(u,true, sizeof(u));
    for(i=2; i<=10000000; i++) {
        if(u[i])
            su[++num]=i;
        for(j=1; j<=num; j++) {
            if(i*su[j]>N)
                break;
            u[i*su[j]]=false;
            if(i%su[j]==0)
                break;
        }
    }
}
 
int main() {
    prepare();
    int n,i,j,k;
    while(scanf("%d",&n)!=EOF&&n>0) {
        if(n<8) {
            puts("NO");
            continue;
        }
        if(u[n-6])
            printf("2 2 2 %d\n",n-6);
        else if(u[n-7])
            printf("2 2 3 %d\n",n-7);
        else if(u[n-8])
            printf("2 3 3 %d\n",n-8);
        else {
            if(n%2==0) {
                printf("2 2 ");
                n-=4;
            } else {
                printf("2 3 ");
                n-=5;
            }
            for(i=1; i<=num; i++) {
                if(su[i]*2>n)
                    break;
                if(u[n-su[i]]) {
                    printf("%d %d\n",su[i],n-su[i]);
                    break;
                }
            }
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/mysh/p/11351244.html