Codeforces Round #520 (Div. 2) B. Math

Posted heyuhhh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #520 (Div. 2) B. Math相关的知识,希望对你有一定的参考价值。

B. Math

time limit per test:1 second
memory limit per test:256 megabytes

Description:

JATC‘s math teacher always gives the class some interesting math problems so that they don‘t get bored. Today the problem is as follows. Given an integer n, you can perform the following operations zero or more times:

  • mul x: multiplies n by x (where x is an arbitrary positive integer).
  • sqrt: replaces nn with n??√n (to apply this operation, n??√n must be an integer).

You can perform these operations as many times as you like. What is the minimum value of n, that can be achieved and what is the minimum number of operations, to achieve that minimum value?

Apparently, no one in the class knows the answer to this problem, maybe you can help them?

Input:

The only line of the input contains a single integer nn (1n10^6,1≤n≤10^6) — the initial number.

Output:

Print two integers: the minimum integer n that can be achieved using the described operations and the minimum number of operations required.

Sample Input:

20

Sample Output:

10 2

 

题意:

对n可以进行开方以及乘以一个数这两种操作(无限次),求经过操作后最小的为多少。

题解:

唯一分解定理告诉我们,n可以分解成若干个质数的成绩,比如n=a1^p1*a2^p2*...*an^pn。

由于可以乘以一个任意的数,所以我们是可以改变p1,p2..pn的值的。我们假定现在已经把指数变为可多次开方的形式,那么最小的n值就是a1*a2*...*an。

现在主要问题是解决操作次数,我们设一个数t,t为2^t>=max(p1,p2,....,pn)的最小值,那么现在我们就可以进行t次开方。

最后再判断一下乘法操作就可以了。

 

代码如下:

技术分享图片
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;

typedef long long LL ;
const int N = 1e6+5;
int tot,n;
int u[N],prim[N],vis[N],a[N];

int main(){
    scanf("%d",&n);
    for(int i=2;i<=sqrt(n);i++){ 
        for(int j=i*i;j<=n;j+=i){
            if(!vis[j]) vis[j]=1;
        }
    }
    for(int i=2;i<=n;i++) if(!vis[i]) prim[++tot]=i;
    int tmp = n,cnt=1;
    while(tmp>1){
        if(tmp%prim[cnt]==0){
            tmp/=prim[cnt];
            a[prim[cnt]]++;
        }else{
            cnt++;
        }
    }
    int maxn = 1;
    cnt=0;
    LL ans = 1,f = 1;
    bool flag=false;
    for(int i=2;i<=n;i++) if(a[i]){
        maxn=max(maxn,a[i]),ans*=i;
    }
    for(int i=2;i<=n;i++){
        if(a[i]&&a[i]!=maxn) flag=true ;
    }
    while(1){
        if(f>=maxn){
            if(flag) break ;
            if(f==maxn) flag=false;else flag=true;
            break;
        }
        f*=2;
        cnt++;
    }
    printf("%lld %d",ans,cnt+(flag==true));
    return 0;
}
View Code

 

后来我看了一下其它人的代码,十分简洁,发现不用把素数给筛出来,具体代码可以看下:

技术分享图片
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

int n,cnt,ans=1;
vector <int > vec ;

int main(){
    scanf("%d",&n);
    int maxn = 0;
    for(int i=2;i<=n;i++){
        cnt = 0;
        if(n%i==0) ans*=i;
        while(n%i==0){
            n/=i;
            cnt++;
        }
        while(1<<(maxn)<cnt) maxn++;
        if(cnt) vec.push_back(cnt);
    }
    int flag = 0;
    for(int i=0;i<vec.size();i++){
        if(vec[i]!=(1<<maxn)) flag=1;
    }
    printf("%d %d",ans,flag+maxn);
    return 0;
}
View Code

 

以上是关于Codeforces Round #520 (Div. 2) B. Math的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #520 (Div. 2) C. Banh-mi

Codeforces Round #520 (Div. 2) D. Fun with Integers

Codeforces Round #436 E. Fire(背包dp+输出路径)

[ACM]Codeforces Round #534 (Div. 2)

Codeforces Round #506 (Div. 3) D-F

Codeforces Round #721 (Div. 2)ABC题解