1. 程式人生 > >Codeforces Round #520 (Div. 2) B. Math

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

scan may nim false operation center codeforce -a val

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