Problem:
Score : 300 points

Problem Statement

There are N integers a_1, a_2, ..., a_N not less than 1.
The values of a_1, a_2, ..., a_N are not known, but it is known that a_1 \times a_2 \times ... \times a_N = P.

Find the maximum possible greatest common divisor of a_1, a_2, ..., a_N.

Constraints

1 \leq N \leq 10^{12}

1 \leq P \leq 10^{12}

Input

Input is given from Standard Input in the following format:

N P

Output

Print the answer.

Sample Input 1

3 24

Sample Output 1

2

The greatest common divisor would be 2 when, for example, a_1=2, a_2=6 and a_3=2.

Sample Input 2

5 1

Sample Output 2

1

As a_i are positive integers, the only possible case is a_1 = a_2 = a_3 = a_4 = a_5 = 1.

Sample Input 3

1 111

Sample Output 3

111

Sample Input 4

4 972439611840

Sample Output 4

206

Solution in C (GCC 5.4.1) (judge verdict: Time Limit Exceeded)

//プリプロセッサ系
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <stdlib.h>
#include <stdbool.h>
#define MOD 1000000007
#define INFTY 2147483646
#define DEBUG 1
#define END printf("\n");return 0;
#define QS09(how_data,data) qsort(data,how_data,sizeof(long),(int (*)(const void *,const void *))qsort_09);
#define QS90(how_data,data) qsort(data,how_data,sizeof(long),(int (*)(const void *,const void *))qsort_90);
//↓この2つはCE対策のために適当にdefineしてるだけだから使う際は「構造体クイックソート設定」をコピペ
#define ST_NAME _GD
#define KEY_NAME how_vertex

#define ST09(how_data,data) qsort(data,how_data,sizeof(ST_NAME),(int (*)(const void *,const void *))qsort_st09);
#define ST90(how_data,data) qsort(data,how_data,sizeof(ST_NAME),(int (*)(const void *,const void *))qsort_st90);
#define In(a) long a;scanf("%ld",&a);
#define Out(a) printf("%ld\n",a);
#define dprintf if(DEBUG)printf
#define ifdebug if(DEBUG)
#define MAKE_ARRAY_DATA In(how_data);long data[how_data];input_array(how_data,data);


//構造体クイックソート設定 使用時はmainに以下をコピペ、ST_NAMEとKEY_NAMEを書き換え
/*
    #undef ST_NAME
    #undef KEY_NAME
    #define ST_NAME _GD
    #define KEY_NAME how_vertex
    ST09(how_data,data);
*/


//関数
void input_array(long how_data,long *data); //配列の入力
void output_array(long how_data,long *data); //配列の出力
void input_array2(long first , long second , long data[][2]); //2次元配列の入力
void format_array(long how_data ,long *data,long what); //配列初期化
long get_random(long min, long max); //min～max範囲の乱数生成
long factorial(long n); //n!
long fibonacci(long n); //n番目のフィボナッチ
int qsort_09(const int *sys1 , const int *sys2);
int qsort_90(const int *sys1 , const int *sys2);
int qsort_st09(const void *c1, const void *c2);
int qsort_st90(const void *c1, const void *c2);
long sel_max(long a , long b);
long sel_min(long a , long b);
long array_max(long how_data,long *data);
long array_min(long how_data,long *data);
long array_search(long how_data,long *data,long what);
long can_DP(long how_data,long *data,long how_can,bool *can);
long array_sum(long how_data,long *data);
long Leven_dist(char *now , char *target);
long get_digit(long target);
long rounding(double target);
long roundingdown(double target);
long roundingup(double target);
long ncr(long n , long r);
long npr(long n , long r);
long nhr(long n , long r);
int fifw(long add,long *data);
long fifr(long *data);
void GRAPH_input(void);
void GRAPH_dfs(long now);
bool check_prime(long target);
long get_lcm(long a,long b);
long get_gcd(long a,long b);
void digit_cut(int how_data,char *s,int *i);  //文字列として与えられた数列を1桁ずつ分割
//グローバル変数一覧
long fifo[1000]={0};//fifo[0]はデータ件数
long loop1,loop2,loop3,loop4,loop5,i_temp;
long g_ans=0; //answerグローバル変数用

typedef struct{
    long how_vertex;
    long how_edge;
    long edge_data[1000][2];
    bool aleady_searched_vertex[500];
    bool all_searched;
} _GD;//GraphData

_GD GRAPH={0,0,{{0}},{0},0};

char c_temp;
//loop5 loop4 loop3 loop2 loop1
//--------------ここから


int main(void){
    In(N);In(P);
    if(N==1){
        printf("%ld",P);
        END;
    }
    //最大公約数を大きくするには？
    //N=1 , P=24 ならば、そのまま24
    //N=2 , P=24 ならば、6と4にわけて、ans=2。 8と3にわけたら1になる 12と2にわけても同じ
    //まずはPを素因数分解すべき？
    //Pの最大値が10^12、因数の数の最大は50個以下(2^50>10^13)
    long insuu_list[50]={0}; //0をNULLとして扱う
    long ct=0; //素因数の数
    long diver=2;
    while(diver!=P+1){
        if(P%diver==0){
            P/=diver;
            insuu_list[ct]=diver;
            //printf("%ld %ld\n",P,insuu_list[ct]);
            diver=1;
            ct++;
        }
        diver++;
    }
    //ここまでで因数リストは完成
    //問題文から、素因数リストの素因数を掛け合わせるなどして、
    //N個の因数にできる(素ではなくなる)
    //最大公約数は、リストの数字がもってる「共通の因数」の最大値
    //どれだけ「共通の因数」を持たせられるか。
    //例えば共通の因数がなければ(数学的に言葉おかしい)(3と8とか)、1となる。
    //例えば、64を2つに分解する時、2と32なら2だが、8と8なら8である。
    //つまり、1箇所に持たせない。
    //同じ因数がN個あれば、それを共通の因数とできる　←これ重要
    //嬉しいことに、先ほどの処理で、リストの因数リストは小さい→大きいにソート済
    
    //for(loop1=0;loop1<ct;loop1++)printf("%d\n",insuu_list[loop1]);
    
    
    long ans=1;
    int temp=insuu_list[0];
    int renzoku=1;
    for(loop1=1;loop1<ct;loop1++){
        if(temp==insuu_list[loop1]){
            renzoku++;
            if(renzoku==N){
                ans*=insuu_list[loop1];
                renzoku=1;
                temp=insuu_list[loop1+1];
                loop1++;
            }
        }else{
            temp=insuu_list[loop1];
            renzoku=1;
        }
    }
    printf("%ld",ans);
    END;
    
    
    
    
}






//--------------ここまで
 
void input_array(long how_data,long *data){
    long loop;
    for(loop=0;loop<how_data;loop++){
        scanf("%ld",&data[loop]);
    }
    return ;
}
void output_array(long how_data,long *data){
    long loop;
    for(loop=0;loop<how_data;loop++){
        printf("%ld ",data[loop]);
    }
    return ;
}
void input_array2(long first,long second,long data[][2]){
    long loopA,loopB;
    for(loopA=0;loopA<first;loopA++){
        for(loopB=0;loopB<second;loopB++){
            scanf("%ld",&data[loopA][loopB]);
        }
    }
    return ;
}
void format_array(long how_data ,long *data,long what){
    long loopA;
    for(loopA=0;loopA<how_data;loopA++){
        data[loopA]=what;
    }
    return ;
}
long get_random(long min, long max){   //指定の範囲から乱数を1つ返すやつ
    //srand((unsigned int)time(0));   //現在時刻で疑似乱数初期化
    rand();rand();rand();rand();    //乱数を空打ち
    return (rand()%(max+1-min))+min;
}
long factorial(long n){//n!のMOD10^9+7を返すやつ
    unsigned long long int ret=1;
    for(long i=1;i<=n;i++)ret=(ret*i)%1000000007;
    return (long)ret;
}
int qsort_09(const int *sys1 , const int *sys2){ //小さいのが上にくるやつ
    //qsort(data,how_data,sizeof(long),(int (*)(const void *,const void *))qsort_09);
    if(*sys1<*sys2){
        return -1;
    }else if(*sys1==*sys2){
        return 0;
    }else{
        return 1;
    }
}
int qsort_90(const int *sys1 , const int *sys2){ //大きいのが上にくるやつ
    //qsort(data,how_data,sizeof(long),(int (*)(const void *,const void *))qsort_90);
    if(*sys1<*sys2){
        return 1;
    }else if(*sys1==*sys2){
        return 0;
    }else{
        return -1;
    }
}
int qsort_st09(const void *c1, const void *c2){
    ST_NAME hikaku1= *(ST_NAME *)c1;
    ST_NAME hikaku2= *(ST_NAME *)c2;
    return hikaku1.KEY_NAME - hikaku2.KEY_NAME;
}
int qsort_st90(const void *c1, const void *c2){
    ST_NAME hikaku1= *(ST_NAME *)c1;
    ST_NAME hikaku2= *(ST_NAME *)c2;
    return hikaku2.KEY_NAME - hikaku1.KEY_NAME;
}
long fibonacci(long n){
    switch(n){
        case 0:return 0;
        case 1:return 1;
        default :return fibonacci(n-1)+fibonacci(n-2);
    }
}
long sel_max(long a,long b){
    if(a>b)return a;
    return b;
}
long sel_min(long a,long b){
    if(a>b)return b;
    return a;
}
long can_DP(long how_data,long *data,long how_can,bool *can){//Typical DP Contest A
    //data内で組み合わせられる和をcanに0 or 1で入れる
    //返り値はパターン数
    long loopA,loopB;
    long ret=0;
    for(loopA=0;loopA<how_can;loopA++){//初期化
        can[loopA]=0;
    }
    can[0]=1;//絶対にありえる
    for(loopA=0;loopA<how_data;loopA++){
        for(loopB=how_can-1;loopB>=0;loopB--){
            if(can[loopB]==1 && loopB+data[loopA]<how_can){
                can[loopB+data[loopA]]=1;
            }
        }
    }
    for(loopA=0;loopA<how_can;loopA++){
        if(can[loopA]==1){
            ret++;
        }
    }
    return ret;
}
long array_max(long how_data,long *data){
    long loop;
    long ret=data[0];
    for(loop=0;loop<how_data;loop++){
        if(ret<data[loop])ret=data[loop];
    }
    return ret;
}
long array_min(long how_data,long *data){
    long loop;
    long ret=data[0];
    for(loop=0;loop<how_data;loop++){
        if(ret>data[loop])ret=data[loop];
    }
    return ret;
}
long array_sum(long how_data,long *data){
    long ret=0;
    long loop;
    for(loop=0;loop<how_data;loop++){
        ret+=data[loop];
    }
    return ret;
}
long array_search(long how_data,long *data,long what){
    long loop;
    for(loop=0;loop<how_data;loop++){
        if(data[loop]==what){
            return loop;
        }
    }
    return -1;
}
long Leven_dist(char *now , char *target){
    long loopA,loopB;
    //レーベンシュタイン距離を求める
    // 参考文献
    // http://nw.tsuda.ac.jp/class/algoB/c13.html  (アルゴリズム理解)
    // http://d.hatena.ne.jp/ohnishiakira/20090809/1249845529  (実装)
    long len_now=strlen(now)+1;
    long len_target=strlen(target)+1;
    long d[len_now][len_target]; //計算用
    for(loopA=0;loopA<len_now;loopA++) d[loopA][0]=loopA;
    for(loopA=0;loopA<len_target;loopA++) d[0][loopA]=loopA;
    for(loopA=1;loopA<len_now;loopA++){
        for(loopB=1;loopB<len_target;loopB++){
            long cost=(now[loopA-1]==target[loopB-1] ? 0:1);
            d[loopA][loopB]=sel_min(sel_min(d[loopA-1][loopB]+1,d[loopA][loopB-1]+1),d[loopA-1][loopB-1]+cost);
        }
    }
    return d[len_now-1][len_target-1];
}
long get_digit(long target){
    return (long)(log10(target)+1);
}
long ncr(long n , long r){
    //パスカルの三角形
    long loopA,loopB;
    long pascal[100][102]={{0}};
    pascal[1][0]=1;
    pascal[1][1]=1;
    for(loopA=2;loopA<100;loopA++){
        pascal[loopA][0]=1;
        for(loopB=1;loopB<loopA;loopB++){
            pascal[loopA][loopB]=pascal[loopA-1][loopB-1]+pascal[loopA-1][loopB];
        }
        pascal[loopA][loopA]=1;
    }
    return pascal[n][r];
}
long npr(long n, long r){
    return ncr(n,r)*factorial(r);
}
long nhr(long n , long r){
    return ncr(n+r-1,r);
}
long rounding(double target){
    return (long)target+0.50;
}
long roundingup(double target){
    return (long)ceil(target);
}
long roundingdown(double target){
    return (long)floor(target);
}
int fifw(long add,long *data){
    data[data[0]+1]=add;
    data[0]++;
    return data[0]; //現在のデータ件数を返す
}
long fifr(long *data){
    long ret=data[1];
    data[0]--;
    for(int i=1;i<999;i++){
        data[i]=data[i+1];
    }
    return ret;
}
void GRAPH_input(void){
    scanf("%ld %ld\n",&GRAPH.how_vertex,&GRAPH.how_edge);
    for(long loopA=0;loopA<GRAPH.how_edge;loopA++){
        scanf("%ld %ld\n",&GRAPH.edge_data[loopA][0],&GRAPH.edge_data[loopA][1]);
    }
    return;
}
void GRAPH_dfs(long now){
    GRAPH.aleady_searched_vertex[now]=1;
    for(int loopA=0;loopA<GRAPH.how_edge;loopA++){
        if(GRAPH.edge_data[loopA][0]==now && GRAPH.aleady_searched_vertex[GRAPH.edge_data[loopA][1]]==0){
            GRAPH_dfs(GRAPH.edge_data[loopA][1]);
        }
        if(GRAPH.edge_data[loopA][1]==now && GRAPH.aleady_searched_vertex[GRAPH.edge_data[loopA][0]]==0){
            GRAPH_dfs(GRAPH.edge_data[loopA][0]);
        }
    }
    return ;
}
bool check_prime(long target){//素数判定、素数なら1
    if(target==2)return 1;
    if(target<=1 || target%2==0)return 0;
    for(int loopA=3;loopA<=sqrt(target)+1;loopA+=2)if(target%loopA==0)return 0;
    return 1;
}
long get_lcm(long a,long b){//最小公倍数
    return (a*b)/get_gcd(a,b);
}
long get_gcd(long a,long b){//最大公約数 参考：https://webkaru.net/clang/find-gcd-of-two-number/
    // a>b
    if(a<b){
        int tem=a;
        a=b;
        b=tem;
    }
    long r=a%b;
    while(r!=0){
        a=b;
        b=r;
        r=a%b;
    }
    return b;
}
void digit_cut(int how_data,char *s,int *i){
    for(int loopA=0;loopA<how_data;loopA++){
        i[loopA]=atoi(&s[loopA]);
    }
    return ;
}